mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-10 20:40:39 +08:00
Merge pull request #1815 from juguagua/leetcode-modify-the-code-of-the-backtracking
更新回溯问题:“重新安排行程” 和 “解数独”
This commit is contained in:
@ -42,9 +42,9 @@
|
||||
|
||||
**如果以上这几道题目没有做过的话,不建议上来就做这道题哈!**
|
||||
|
||||
[N皇后问题](https://programmercarl.com/0051.N皇后.html)是因为每一行每一列只放一个皇后,只需要一层for循环遍历一行,递归来来遍历列,然后一行一列确定皇后的唯一位置。
|
||||
[N皇后问题](https://programmercarl.com/0051.N皇后.html)是因为每一行每一列只放一个皇后,只需要一层for循环遍历一行,递归来遍历列,然后一行一列确定皇后的唯一位置。
|
||||
|
||||
本题就不一样了,**本题中棋盘的每一个位置都要放一个数字(而N换后是一行只放一个皇后),并检查数字是否合法,解数独的树形结构要比N皇后更宽更深**。
|
||||
本题就不一样了,**本题中棋盘的每一个位置都要放一个数字(而N皇后是一行只放一个皇后),并检查数字是否合法,解数独的树形结构要比N皇后更宽更深**。
|
||||
|
||||
因为这个树形结构太大了,我抽取一部分,如图所示:
|
||||
|
||||
@ -75,7 +75,7 @@ bool backtracking(vector<vector<char>>& board)
|
||||
|
||||
**那么有没有永远填不满的情况呢?**
|
||||
|
||||
这个问题我在递归单层搜索逻辑里在来讲!
|
||||
这个问题我在递归单层搜索逻辑里再来讲!
|
||||
|
||||
* 递归单层搜索逻辑
|
||||
|
||||
@ -207,7 +207,7 @@ public:
|
||||
|
||||
所以我在开篇就提到了**二维递归**,这也是我自创词汇,希望可以帮助大家理解解数独的搜索过程。
|
||||
|
||||
一波分析之后,在看代码会发现其实也不难,唯一难点就是理解**二维递归**的思维逻辑。
|
||||
一波分析之后,再看代码会发现其实也不难,唯一难点就是理解**二维递归**的思维逻辑。
|
||||
|
||||
**这样,解数独这么难的问题,也被我们攻克了**。
|
||||
|
||||
@ -331,55 +331,56 @@ class Solution:
|
||||
### Go
|
||||
|
||||
```go
|
||||
func solveSudoku(board [][]byte) {
|
||||
var backtracking func(board [][]byte) bool
|
||||
backtracking=func(board [][]byte) bool{
|
||||
for i:=0;i<9;i++{
|
||||
for j:=0;j<9;j++{
|
||||
//判断此位置是否适合填数字
|
||||
if board[i][j]!='.'{
|
||||
continue
|
||||
}
|
||||
//尝试填1-9
|
||||
for k:='1';k<='9';k++{
|
||||
if isvalid(i,j,byte(k),board)==true{//如果满足要求就填
|
||||
board[i][j]=byte(k)
|
||||
if backtracking(board)==true{
|
||||
return true
|
||||
}
|
||||
board[i][j]='.'
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
backtracking(board)
|
||||
func solveSudoku(board [][]byte) {
|
||||
var backtracking func(board [][]byte) bool
|
||||
backtracking = func(board [][]byte) bool {
|
||||
for i := 0; i < 9; i++ {
|
||||
for j := 0; j < 9; j++ {
|
||||
//判断此位置是否适合填数字
|
||||
if board[i][j] != '.' {
|
||||
continue
|
||||
}
|
||||
//尝试填1-9
|
||||
for k := '1'; k <= '9'; k++ {
|
||||
if isvalid(i, j, byte(k), board) == true { //如果满足要求就填
|
||||
board[i][j] = byte(k)
|
||||
if backtracking(board) == true {
|
||||
return true
|
||||
}
|
||||
board[i][j] = '.'
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
backtracking(board)
|
||||
}
|
||||
|
||||
//判断填入数字是否满足要求
|
||||
func isvalid(row,col int,k byte,board [][]byte)bool{
|
||||
for i:=0;i<9;i++{//行
|
||||
if board[row][i]==k{
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i:=0;i<9;i++{//列
|
||||
if board[i][col]==k{
|
||||
return false
|
||||
}
|
||||
}
|
||||
//方格
|
||||
startrow:=(row/3)*3
|
||||
startcol:=(col/3)*3
|
||||
for i:=startrow;i<startrow+3;i++{
|
||||
for j:=startcol;j<startcol+3;j++{
|
||||
if board[i][j]==k{
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
func isvalid(row, col int, k byte, board [][]byte) bool {
|
||||
for i := 0; i < 9; i++ { //行
|
||||
if board[row][i] == k {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for i := 0; i < 9; i++ { //列
|
||||
if board[i][col] == k {
|
||||
return false
|
||||
}
|
||||
}
|
||||
//方格
|
||||
startrow := (row / 3) * 3
|
||||
startcol := (col / 3) * 3
|
||||
for i := startrow; i < startrow+3; i++ {
|
||||
for j := startcol; j < startcol+3; j++ {
|
||||
if board[i][j] == k {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -86,7 +86,7 @@ unordered_map<string, map<string, int>> targets:unordered_map<出发机场, ma
|
||||
在遍历 `unordered_map<出发机场, map<到达机场, 航班次数>> targets`的过程中,**可以使用"航班次数"这个字段的数字做相应的增减,来标记到达机场是否使用过了。**
|
||||
|
||||
|
||||
如果“航班次数”大于零,说明目的地还可以飞,如果如果“航班次数”等于零说明目的地不能飞了,而不用对集合做删除元素或者增加元素的操作。
|
||||
如果“航班次数”大于零,说明目的地还可以飞,如果“航班次数”等于零说明目的地不能飞了,而不用对集合做删除元素或者增加元素的操作。
|
||||
|
||||
**相当于说我不删,我就做一个标记!**
|
||||
|
||||
@ -439,68 +439,6 @@ func findItinerary(tickets [][]string) []string {
|
||||
}
|
||||
```
|
||||
|
||||
### C语言
|
||||
|
||||
```C
|
||||
char **result;
|
||||
bool *used;
|
||||
int g_found;
|
||||
|
||||
int cmp(const void *str1, const void *str2)
|
||||
{
|
||||
const char **tmp1 = *(char**)str1;
|
||||
const char **tmp2 = *(char**)str2;
|
||||
int ret = strcmp(tmp1[0], tmp2[0]);
|
||||
if (ret == 0) {
|
||||
return strcmp(tmp1[1], tmp2[1]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void backtracting(char *** tickets, int ticketsSize, int* returnSize, char *start, char **result, bool *used)
|
||||
{
|
||||
if (*returnSize == ticketsSize + 1) {
|
||||
g_found = 1;
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < ticketsSize; i++) {
|
||||
if ((used[i] == false) && (strcmp(start, tickets[i][0]) == 0)) {
|
||||
result[*returnSize] = (char*)malloc(sizeof(char) * 4);
|
||||
memcpy(result[*returnSize], tickets[i][1], sizeof(char) * 4);
|
||||
(*returnSize)++;
|
||||
used[i] = true;
|
||||
/*if ((*returnSize) == ticketsSize + 1) {
|
||||
return;
|
||||
}*/
|
||||
backtracting(tickets, ticketsSize, returnSize, tickets[i][1], result, used);
|
||||
if (g_found) {
|
||||
return;
|
||||
}
|
||||
(*returnSize)--;
|
||||
used[i] = false;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
char ** findItinerary(char *** tickets, int ticketsSize, int* ticketsColSize, int* returnSize){
|
||||
if (tickets == NULL || ticketsSize <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
result = malloc(sizeof(char*) * (ticketsSize + 1));
|
||||
used = malloc(sizeof(bool) * ticketsSize);
|
||||
memset(used, false, sizeof(bool) * ticketsSize);
|
||||
result[0] = malloc(sizeof(char) * 4);
|
||||
memcpy(result[0], "JFK", sizeof(char) * 4);
|
||||
g_found = 0;
|
||||
*returnSize = 1;
|
||||
qsort(tickets, ticketsSize, sizeof(tickets[0]), cmp);
|
||||
backtracting(tickets, ticketsSize, returnSize, "JFK", result, used);
|
||||
*returnSize = ticketsSize + 1;
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
```Javascript
|
||||
|
||||
@ -589,6 +527,68 @@ function findItinerary(tickets: string[][]): string[] {
|
||||
};
|
||||
```
|
||||
|
||||
### C语言
|
||||
|
||||
```C
|
||||
char **result;
|
||||
bool *used;
|
||||
int g_found;
|
||||
|
||||
int cmp(const void *str1, const void *str2)
|
||||
{
|
||||
const char **tmp1 = *(char**)str1;
|
||||
const char **tmp2 = *(char**)str2;
|
||||
int ret = strcmp(tmp1[0], tmp2[0]);
|
||||
if (ret == 0) {
|
||||
return strcmp(tmp1[1], tmp2[1]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void backtracting(char *** tickets, int ticketsSize, int* returnSize, char *start, char **result, bool *used)
|
||||
{
|
||||
if (*returnSize == ticketsSize + 1) {
|
||||
g_found = 1;
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < ticketsSize; i++) {
|
||||
if ((used[i] == false) && (strcmp(start, tickets[i][0]) == 0)) {
|
||||
result[*returnSize] = (char*)malloc(sizeof(char) * 4);
|
||||
memcpy(result[*returnSize], tickets[i][1], sizeof(char) * 4);
|
||||
(*returnSize)++;
|
||||
used[i] = true;
|
||||
/*if ((*returnSize) == ticketsSize + 1) {
|
||||
return;
|
||||
}*/
|
||||
backtracting(tickets, ticketsSize, returnSize, tickets[i][1], result, used);
|
||||
if (g_found) {
|
||||
return;
|
||||
}
|
||||
(*returnSize)--;
|
||||
used[i] = false;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
char ** findItinerary(char *** tickets, int ticketsSize, int* ticketsColSize, int* returnSize){
|
||||
if (tickets == NULL || ticketsSize <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
result = malloc(sizeof(char*) * (ticketsSize + 1));
|
||||
used = malloc(sizeof(bool) * ticketsSize);
|
||||
memset(used, false, sizeof(bool) * ticketsSize);
|
||||
result[0] = malloc(sizeof(char) * 4);
|
||||
memcpy(result[0], "JFK", sizeof(char) * 4);
|
||||
g_found = 0;
|
||||
*returnSize = 1;
|
||||
qsort(tickets, ticketsSize, sizeof(tickets[0]), cmp);
|
||||
backtracting(tickets, ticketsSize, returnSize, "JFK", result, used);
|
||||
*returnSize = ticketsSize + 1;
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
### Swift
|
||||
|
||||
直接迭代tickets数组:
|
||||
@ -709,78 +709,6 @@ for line in tickets {
|
||||
}
|
||||
```
|
||||
|
||||
### Go
|
||||
```Go
|
||||
|
||||
// 先排序,然后找到第一条路径即可返回
|
||||
func findItinerary(tickets [][]string) []string {
|
||||
var path []string // 用来保存搜索的路径
|
||||
data := make(map[string]ticketSlice) // 用来保存tickets排序后的结果
|
||||
|
||||
var search func(airport string) bool
|
||||
search = func(airport string) bool {
|
||||
if len(path) == len(tickets) {
|
||||
path = append(path, airport)
|
||||
return true
|
||||
}
|
||||
to := data[airport]
|
||||
for _, item := range to {
|
||||
if item.Count == 0 {
|
||||
// 已用完
|
||||
continue
|
||||
}
|
||||
|
||||
path = append(path, airport)
|
||||
item.Count--
|
||||
if search(item.To) { return true }
|
||||
item.Count++
|
||||
path = path[:len(path) - 1]
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// 排序
|
||||
// 感觉这段代码有点啰嗦,不知道能不能简化一下
|
||||
tmp := make(map[string]map[string]int)
|
||||
for _, ticket := range tickets {
|
||||
if to, ok := tmp[ticket[0]]; ok {
|
||||
if _, ok2 := to[ticket[1]]; ok2 {
|
||||
to[ticket[1]]++
|
||||
} else {
|
||||
to[ticket[1]] = 1
|
||||
}
|
||||
} else {
|
||||
tmp[ticket[0]] = map[string]int{
|
||||
ticket[1]: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
for from, to := range tmp {
|
||||
var tmp ticketSlice
|
||||
for to, num := range to {
|
||||
tmp = append(tmp, &ticketStat{To: to, Count: num})
|
||||
}
|
||||
sort.Sort(tmp)
|
||||
data[from] = tmp
|
||||
}
|
||||
|
||||
search("JFK")
|
||||
return path
|
||||
}
|
||||
|
||||
type ticketStat struct {
|
||||
To string
|
||||
Count int
|
||||
}
|
||||
type ticketSlice []*ticketStat
|
||||
|
||||
func (p ticketSlice) Len() int { return len(p) }
|
||||
func (p ticketSlice) Less(i, j int) bool { return strings.Compare(p[i].To, p[j].To) == -1 }
|
||||
func (p ticketSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||
|
||||
```
|
||||
|
||||
### Rust
|
||||
** 文中的Hashmap嵌套Hashmap的方法因为Rust的所有权问题暂时无法实现,此方法为删除哈希表中元素法 **
|
||||
```Rust
|
||||
|
Reference in New Issue
Block a user