每日刷题(5)——回溯问题:N皇后、解数独、重新安排行程
创始人
2024-06-02 16:52:25
0

本篇文章题目来源于leetcode与代码随想录

前言

哈喽,大家好,我是小雨,今天做了代码随想录的回溯部分,其中连续三个困难题非常有价值,本篇文章就来聊聊这三个困难题:

51. N 皇后 - 力扣(Leetcode)

37. 解数独 - 力扣(Leetcode)

332. 重新安排行程 - 力扣(Leetcode)

Question 51. N 皇后

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q''.' 分别代表了皇后和空位。

示例 1:

输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:'Q'表示皇后位置,'.'表示空位置,如图,4 皇后问题存在两个不同的解法。

提示:

  • 1 <= n <= 9

Solution

此题是很经典的回溯问题,我们从第一行开始放置皇后,尝试在每个位置放置皇后,然后递归到下一行,继续尝试放置皇后,直到所有行都被填满或无法继续放置皇后为止。如果在某一行无法找到合适的位置放置皇后,则需要回溯到上一行,并尝试在上一行的其他位置放置皇后。在实现回溯算法时,需要使用一个temp数组来记录每一行中皇后的位置,以及一个visited数组来记录当前位置是否可以走到。实现的具体代码如下:

Code

func getResult(temp []int)[]string{var result []stringn:=len(temp)for i := 0; i < len(temp); i++ {var s []bytefor j := 0; j < n; j++ {if j == temp[i]{s = append(s,'Q')}else{s = append(s,'.')}}result =append(result,string(s))}return result
}func solveNQueens(n int) [][]string {var temp []intvar result [][]stringvisited := make([][]int,n)for i := 0; i < len(visited); i++ {visited[i] = make([]int,n)}var dfs func(index int)dfs = func(index int) {if len(temp) == n {fmt.Println(temp)result = append(result,getResult(temp))return }for i := 0; i < n; i++ {if visited[index][i] > 0 {continue}//修改visited数组for j := 0; j < n; j++ {visited[index][j]++}for j := 0; j < n; j++ {visited[j][i]++}//斜右下x,y:=index+1,i+1for x < n && y < n {visited[x][y]++x++y++}//斜左下x,y = index+1,i-1for x < n && y >= 0 {visited[x][y]++x++y--}//放入temp中temp = append(temp,i)dfs(index+1)//还原visited数组//修改visited数组for j := 0; j < n; j++ {visited[index][j]--}for j := 0; j < n; j++ {visited[j][i]--}//斜右下x,y = index+1,i+1for x < n && y < n {visited[x][y]--x++y++}//斜左下x,y = index+1,i-1for x < n && y >= 0 {visited[x][y]--x++y--}//还原temptemp = temp[:len(temp)-1]}}dfs(0)return result}

Question 37. 解数独

编写一个程序,通过填充空格来解决数独问题。

数独的解法需 遵循如下规则

  1. 数字 1-9 在每一行只能出现一次。
  2. 数字 1-9 在每一列只能出现一次。
  3. 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

数独部分空格内已填入了数字,空白格用 '.' 表示。

示例 1:

输入:board = [["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]]
输出:[["5","3","4","6","7","8","9","1","2"],["6","7","2","1","9","5","3","4","8"],["1","9","8","3","4","2","5","6","7"],["8","5","9","7","6","1","4","2","3"],["4","2","6","8","5","3","7","9","1"],["7","1","3","9","2","4","8","5","6"],["9","6","1","5","3","7","2","8","4"],["2","8","7","4","1","9","6","3","5"],["3","4","5","2","8","6","1","7","9"]]

提示:

  • board.length == 9
  • board[i].length == 9
  • board[i][j] 是一位数字或者 '.'
  • 题目数据 保证 输入数独仅有一个解

Solution

解决数独问题也可以使用回溯算法,类似于 N 皇后问题。从第一个空格开始,尝试在该位置填入数字 1-9,然后递归到下一个空格,继续尝试填入数字,直到所有空格都被填满或无法继续填入数字为止。如果在某一格无法找到合适的数字填入,则需要回溯到上一个空格,并尝试填入其他数字。实现时,我们需要额外定义三个数组,来记录横向竖向和网格的数字出现情况,具体实现如下:

Code

func solveSudoku(board [][]byte)  {hvisited := make([][]int,9)svisited := make([][]int,9)xvisited := make([][]int,9)for i := 0; i < 9; i++ {hvisited[i] = make([]int,10)svisited[i] = make([]int,10)xvisited[i] = make([]int,10)}//初始化visited数组for i := 0; i < len(board); i++ {for j := 0; j < len(board[i]); j++ {temp:=board[i][j]if temp != '.'{hvisited[i][temp-'0']++svisited[j][temp-'0']++xvisited[(i/3)*3+(j/3)][temp-'0']++}}}var help func(x,y int)(int,int) = func(x, y int) (int, int) {x += y/9y %= 9return x,y}var visited func(x,y,i int)bool = func(x,y,i int)bool{if hvisited[x][i] >0 || svisited[y][i] > 0 || xvisited[(x/3)*3+(y/3)][i]>0{return true}else {return false}}var dfs func(x,y int)booldfs = func(x, y int) bool{if x == 9 {return true}if board[x][y] != '.'{if dfs(help(x,y+1)){return true}}else{for i := 1; i <= 9; i++ {if visited(x,y,i){continue}hvisited[x][i]++svisited[y][i]++xvisited[(x/3)*3+(y/3)][i]++board[x][y] = byte('0'+i) if dfs(help(x,y+1)){return true}board[x][y] = byte('.')hvisited[x][i]--svisited[y][i]--xvisited[(x/3)*3+(y/3)][i]--}}return false}dfs(0,0)}

Question 332. 重新安排行程

给你一份航线列表 tickets ,其中 tickets[i] = [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。

所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。

  • 例如,行程 ["JFK", "LGA"]["JFK", "LGB"] 相比就更小,排序更靠前。

假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。

示例 1:

输入:tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]
输出:["JFK","MUC","LHR","SFO","SJC"]

提示:

  • 1 <= tickets.length <= 300
  • tickets[i].length == 2
  • fromi.length == 3
  • toi.length == 3
  • fromitoi 由大写英文字母组成
  • fromi != toi

Solution

在这题中,定义一个hashmap,存储车站与到达车站的映射。首先遍历车票,将车票中出发站和到达站的映射进行存储,从起点开始,依次尝试每一张机票,检查它是否符合要求(即当前机场为起点,且这张机票没有被使用过),如果符合要求,则将其加入当前路径中,并继续搜索下一个机场;如果不符合要求,则回溯到上一个机场,并继续尝试其他机票。当路径长度等于机场数量时,说明我们已经找到了一条合法的路径(注意,题目要求按字典排序返回最小的行程组合,因此如果提前对映射中的到达站进行排序,那么第一个遍历到的结果就是字典序最小的结果),返回结果即可。

Code

func findItinerary(tickets [][]string) []string {m := make(map[string][]string)var result []stringvar temp []stringvar dfs func(s string)var flag boolfor i := 0; i < len(tickets); i++ {m[tickets[i][0]] = append(m[tickets[i][0]],tickets[i][1])}for _,v:=range m {sort.Slice(v, func(i, j int) bool {if v[i] < v[j]{return true}else{return false}})}temp = append(temp,"JFK")dfs = func(s string) {if flag {return }if len(temp) == len(tickets)+1{result = make([]string,len(temp))copy(result,temp)flag = truereturn}for i,v:=range m[s]{if v =="-1"{continue}temp = append(temp,v)m[s][i] = "-1"dfs(v)temp = temp[:len(temp)-1]m[s][i] = v}}dfs("JFK")return result
}

总结

在做回溯类题目时,最好能够画出树状图,确定回溯路线,对整个题目做个大概的模拟,如果模拟成功,即可开始实现。实现时,定义一些状态信息,随后编写回溯函数,注意,横向的遍历由for循环控制竖向的递归由dfs函数控制,最后再针对每种类型的题目进行减枝操作即可!

相关内容

热门资讯

中斯新能源合作迈入新阶段 转自:光明日报  【机遇东方来】  近期,斯洛伐克政府宣布西部舒拉尼工业园区投资项目上升为国家战略投...
证监会:从五方面健全投资者保护... ◎记者 梁银妍 汤立斌 中国证监会副主席陈华平5月15日在2025年“5·15全国投资者保护宣传日”...
嘉泽新能陈波:前瞻布局抢抓“新... ◎记者 于瑶 面对激烈的市场竞争,新能源发电企业如何及时调整布局、加速转型升级并抢抓发展机遇?近日,...
证监会举办“5·15全国投资者... 高晓力表示,最高法将依法严厉打击欺诈发行、违规信息披露等财务造假违法犯罪行为,坚持“追首恶”“打帮凶...
中国将对巴西等5国试行免签政策     外交部发言人林剑15日在例行记者会上说,为进一步便利中外人员往来,中方决定扩大免签国家范围,...
2025青海文化旅游节5月19... 本报讯(西海新闻记者 吴梦婷)记者从2025青海文化旅游节新闻发布会了解到,2025青海文化旅游节以...
罗东川会见北京大学校长龚旗煌 ... 本报讯(记者 田得乾 石成砚)5月15日,省委副书记、省长罗东川在西宁会见北京大学校长、中国科学院院...
重庆奉节“科技小院”让村民尝到... 本报讯(记者黄仕强)“2024年村民户均收入超过12万元,村集体经济收入突破300万元。”5月14日...
无强制评级后信评格局生变:主体... 自2021年证监会、交易商协会逐步取消债券发行环节的强制评级要求后,去年已是我国债券市场无强制评级的...
内蒙古首个“绿电直供”算力中心... 转自:内蒙古日报本报5月15日讯  (记者  康丽娜)记者从自治区能源局获悉,“全国一体化算力网络”...
老人的两万元不翼而飞 民警快速... 本报讯(西海新闻记者 郭红霞)“多亏了宝库派出所的民警,不然两万元就没了。”5月14日,说起前几天发...
西宁城中“宁晓哥”小程序上线 本报讯(西海新闻记者 燕卓)5月14日,记者从西宁市城中区获悉,为给快递员、外卖配送员、网约车司机等...
风电设备生产忙 转自:内蒙古日报5月14日,运达股份北方总部(乌兰察布)智能产业基地生产车间内工人们有序工作,确保风...
红色话剧《我们正青春年少》走进... 本报石河子讯(全媒体记者 史进 通讯员 李凤华) 日前,新疆大学原创红色话剧《我们正青春年少...
青海举办“5·15”打击和防范... 本报讯(西海新闻记者 何耀军)2025年5月15日是第16个全国公安机关打击和防范经济犯罪宣传日。青...
中方将对巴西等五国试行免签政策   新华社北京5月15日电外交部发言人林剑15日在例行记者会上说,为进一步便利中外人员往来,中方决定...
【促进民营经济高质量发展】河南... 本报讯(记者余嘉熙 通讯员葛慧君)蜜雪冰城从郑州一家街头小店,发展成全球最大现制饮品企业,并在港交所...
“青铜之光——古蜀文明特展”在... 近日,“青铜之光——古蜀文明特展”在新斯米尔尼市政博物馆开幕。展览通过精美的文物复制品、3D打印技术...
人工智能教育指南深意何在     徐向东    近日,教育部基础教育教学指导委员会发布《中小学人工智能通识教育指南(2025年...
兵团投入2081万元推动文旅产... 本报乌鲁木齐讯(全媒体记者 张美玲) 记者从兵团财政局获悉,今年,兵团本级财政统筹专项资金20...