赞
踩
一、递归、深搜、穷举vs暴搜vs深搜vs回溯vs剪枝:
- class Solution
- {
- public:
- void hanota(vector<int>& a, vector<int>& b, vector<int>& c)
- {
- dfs(a, b, c, a.size());
- }
-
- void dfs(vector<int>& a, vector<int>& b, vector<int>& c, int n)
- {
- if(n == 1)
- {
- c.push_back(a.back());
- a.pop_back();
- return;
- }
-
- dfs(a, c, b, n - 1);
- c.push_back(a.back());
- a.pop_back();
- dfs(b, a, c, n - 1);
- }
- };
02、21. 合并两个有序链表
- class Solution
- {
- public:
- ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
- {
- if(l1 == nullptr) return l2;
- if(l2 == nullptr) return l1;
-
- if(l1->val <= l2->val)
- {
- l1->next = mergeTwoLists(l1->next, l2);
- return l1;
- }
- else
- {
- l2->next = mergeTwoLists(l1, l2->next);
- return l2;
- }
- }
- };
总结:
①循环(迭代)vs递归:分支越多,递归越爽;分支又少又长,则用循环(否则容易栈溢出)。
②递归的展开图,其实就是对一棵树做一次深度优先遍历(dfs)。
03、206. 反转链表
- class Solution
- {
- public:
- ListNode* reverseList(ListNode* head)
- {
- if(head == nullptr || head -> next == nullptr) return head;
- ListNode* newhead = reverseList(head->next);
- head->next->next = head;
- head->next = nullptr;
- return newhead;
- }
- };
- class Solution
- {
- public:
- ListNode* swapPairs(ListNode* head)
- {
- if(head == nullptr || head->next == nullptr) return head;
-
- auto tmp = swapPairs(head->next->next);
- auto ret = head->next;
- head->next->next = head;
- head->next = tmp;
-
- return ret;
- }
- };
解法快速幂 O(N):
- class Solution
- {
- public:
- double myPow(double x, int n)
- {
- return n < 0 ? 1.0 / pow(x, -(long long)n) : pow(x, n);
- }
-
- double pow(double x, long long n)
- {
- if(n == 0) return 1.0;
- auto tmp = pow(x, n / 2);
- return n % 2 == 0 ? tmp * tmp : tmp * tmp * x;
- }
- };
- class Solution
- {
- public:
- bool evaluateTree(TreeNode* root)
- {
- if(root->left == nullptr) return root->val == 0 ? false : true;
-
- bool left = evaluateTree(root->left);
- bool right = evaluateTree(root->right);
-
- return root->val == 2 ? left | right : left & right;
- }
- };
- class Solution
- {
- public:
- int sumNumbers(TreeNode* root)
- {
- return dfs(root, 0);
- }
-
- int dfs(TreeNode* root, int presum)
- {
- presum = presum * 10 + root->val;
- if(root->left == nullptr && root->right == nullptr) return presum;
- int ret = 0;
- if(root->left) ret += dfs(root->left, presum);
- if(root->right) ret += dfs(root->right, presum);
- return ret;
- }
- };
08、814. 二叉树剪枝
- class Solution
- {
- public:
- TreeNode* pruneTree(TreeNode* root)
- {
- if(root == nullptr) return nullptr;
-
- root->left = pruneTree(root->left);
- root->right = pruneTree(root->right);
-
- if(root->left == nullptr && root->right == nullptr && root->val == 0)
- {
- delete root; // 防止内存泄漏
- root = nullptr;
- }
- return root;
- }
- };
09、98. 验证二叉搜索树
- class Solution
- {
- long prev = LONG_MIN;
- public:
- bool isValidBST(TreeNode* root)
- {
- if(root == nullptr) return true;
-
- bool left = isValidBST(root->left);
- // 剪枝
- if(left == false) return false;
- bool cur = false;
- if(root->val > prev) cur = true;
- // 剪枝
- if(cur == false) return false;
- prev = root->val;
- bool right = isValidBST(root->right);
-
- return left && right && cur;
- }
- };
- class Solution
- {
- int count = 0;
- int ret = 0;
- public:
- int kthSmallest(TreeNode* root, int k)
- {
- count = k;
- dfs(root);
- return ret;
- }
-
- void dfs(TreeNode* root)
- {
- if(root == nullptr || count == 0) return;
-
- dfs(root->left);
- count--;
- if(count == 0) ret = root->val;
- dfs(root->right);
- }
- };
- class Solution
- {
- vector<string> ret;
- public:
- vector<string> binaryTreePaths(TreeNode* root)
- {
- string path; // 不能设置全局变量,否则要手动恢复现场
- if(root->nullptr) return ret;
- dfs(root, path);
- return ret;
- }
-
- void dfs(TreeNode* root, string path) // 不能引用,否则要手动恢复现场
- {
- path += to_string(root->val);
- if(root->left == nullptr && root->right == nullptr)
- {
- ret.push_back(path);
- return;
- }
- path += "->";
- if(root->left) dfs(root->left, path); // 剪枝
- if(root->right) dfs(root->right, path); // 剪枝
- }
- };
12、46. 全排列
- // 决策树
- class Solution
- {
- vector<vector<int>> ret;
- vector<int> path;
- bool check[7];
- public:
- vector<vector<int>> permute(vector<int>& nums)
- {
- dfs(nums);
- return ret;
- }
-
- void dfs(vector<int>& nums)
- {
- if(path.size() == nums.size())
- {
- ret.push_back(path);
- return;
- }
-
- for(int i = 0; i < nums.size(); i++)
- {
- if(check[i] == false)
- {
- path.push_back(nums[i]);
- check[i] = true;
- dfs(nums);
- // 回溯 -> 恢复现场
- path.pop_back();
- check[i] = false;
- }
- }
- }
- };
13、78. 子集
解法一:
- class Solution
- {
- vector<vector<int>> ret;
- vector<int> path;
- public:
- vector<vector<int>> subsets(vector<int>& nums)
- {
- dfs(nums, 0);
- return ret;
- }
-
- void dfs(vector<int>& nums, int pos)
- {
- if(pos == nums.size())
- {
- ret.push_back(path);
- return;
- }
-
- // 选
- path.push_back(nums[pos]);
- dfs(nums, pos + 1);
- path.pop_back(); // 恢复现场
-
- // 不选
- dfs(nums, pos + 1);
- }
- };
解法二:
- class Solution
- {
- vector<vector<int>> ret;
- vector<int> path;
- public:
- vector<vector<int>> subsets(vector<int>& nums)
- {
- // 解法二:
- dfs(nums, 0);
- return ret;
- }
-
- void dfs(vector<int>& nums, int pos)
- {
- ret.push_back(path);
- for(int i = pos; i < nums.size(); i++)
- {
- path.push_back(nums[i]);
- dfs(nums, i + 1);
- path.pop_back(); // 恢复现场
- }
- }
- };
- class Solution
- {
- int path = 0;
- int sum = 0;
- public:
- int subsetXORSum(vector<int>& nums)
- {
- dfs(nums, 0);
- return sum;
- }
-
- void dfs(vector<int>& nums, int pos)
- {
- sum += path;
- for(int i = pos; i < nums.size(); i++)
- {
- path ^= nums[i];
- dfs(nums, i + 1);
- path ^= nums[i]; // 亦或运算:消消乐
- }
- }
- };
15、47. 全排列 II
算法原理:
前提:先把整个数组排序。
剪枝:
①同一个节点的不同分支中,相同的元素只能选择一次。
②同一个数只能选择一次->check。
两种解法:
①只关心“不合法”的分支。
- class Solution
- {
- vector<vector<int>> ret;
- vector<int> path;
- bool check[10];
- public:
- vector<vector<int>> permuteUnique(vector<int>& nums)
- {
- sort(nums.begin(), nums.end());
-
- dfs(nums, 0);
- return ret;
- }
-
- void dfs(vector<int>& nums, int pos)
- {
- if(pos == nums.size())
- {
- ret.push_back(path);
- return;
- }
-
- for(int i = 0; i < nums.size(); i++)
- {
- // 剪枝
- if(check[i] == true || (i != 0 && nums[i] == nums[i - 1] && check[i - 1] == false))
- continue;
- path.push_back(nums[i]);
- check[i] = true;
- dfs(nums, pos + 1);
- path.pop_back(); // 恢复现场
- check[i] = false;
- }
- }
- };
②只关心“合法”的分支。
- class Solution
- {
- vector<vector<int>> ret;
- vector<int> path;
- bool check[10];
- public:
- vector<vector<int>> permuteUnique(vector<int>& nums)
- {
- sort(nums.begin(), nums.end());
- dfs(nums, 0);
- return ret;
- }
-
- void dfs(vector<int>& nums, int pos)
- {
- if(pos == nums.size())
- {
- ret.push_back(path);
- return;
- }
-
- for(int i = 0; i < nums.size(); i++)
- {
- // 剪枝
- if(check[i] == false && (i == 0 || nums[i - 1] != nums[i] || check[i - 1] != false))
- {
- path.push_back(nums[i]);
-
- check[i] = true;
- dfs(nums, pos + 1);
- path.pop_back(); // 恢复现场
- check[i] = false;
- }
- }
- }
- };
- class Solution
- {
- string hash[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
- string path;
- vector<string> ret;
- public:
- vector<string> letterCombinations(string digits)
- {
- if(digits.size() == 0) return ret;
- dfs(digits, 0);
- return ret;
- }
-
- void dfs(string& digits, int pos)
- {
- if(pos == digits.size())
- {
- ret.push_back(path);
- return;
- }
-
- for(auto ch : hash[digits[pos] - '0'])
- {
- path.push_back(ch);
- dfs(digits,pos + 1);
- path.pop_back();
- }
- }
- };
17、22. 括号生成
有效的括号组合:
①左括号的数量=有括号的数量。
②从头开始的任意一个字串,左括号的数量>=右括号的数量。
- class Solution
- {
- int left, right, n;
- vector<string> ret;
- string path;
- public:
- vector<string> generateParenthesis(int _n)
- {
- n = _n;
- dfs();
- return ret;
- }
-
- void dfs()
- {
- // 递归出口
- if(right == n)
- {
- ret.push_back(path);
- return;
- }
-
- if(left < n) // 添加左括号
- {
- path.push_back('(');
- left++;
- dfs();
- path.pop_back(); // 恢复现场
- left--;
- }
-
- if(right < left) // 添加右括号
- {
- path.push_back(')');
- right++;
- dfs();
- path.pop_back(); // 恢复现场
- right--;
- }
- }
- };
18、77. 组合
- class Solution
- {
- int n, k;
- vector<vector<int>> ret;
- vector<int> path;
- public:
- vector<vector<int>> combine(int _n, int _k)
- {
- n = _n;
- k = _k;
- dfs(1);
- return ret;
- }
-
- void dfs(int start)
- {
- if(path.size() == k)
- {
- ret.push_back(path);
- return;
- }
-
- for(int i = start; i <= n; i++) // 剪枝
- {
- path.push_back(i);
- dfs(i + 1);
- path.pop_back(); // 恢复现场
- }
- }
- };
19、494. 目标和
path作为全局变量:
- class Solution
- {
- int path, ret, aim;
- public:
- int findTargetSumWays(vector<int>& nums, int target)
- {
- aim = target;
- dfs(nums, 0);
- return ret;
- }
-
- void dfs(vector<int>& nums, int pos)
- {
- if(pos == nums.size())
- {
- if(path == aim) ret++;
- return;
- }
-
- // 加法
- path += nums[pos];
- dfs(nums, pos + 1);
- path -= nums[pos]; // 恢复现场
-
- // 减法
- path -= nums[pos];
- dfs(nums, pos + 1);
- path += nums[pos]; // 恢复现场
- }
- };
path作为参数:
- class Solution
- {
- int ret, aim;
- public:
- int findTargetSumWays(vector<int>& nums, int target)
- {
- aim = target;
- dfs(nums, 0, 0);
- return ret;
- }
-
- void dfs(vector<int>& nums, int pos,int path)
- {
- if(pos == nums.size())
- {
- if(path == aim) ret++;
- return;
- }
-
- // 加法
- dfs(nums, pos + 1, path + nums[pos]);
-
- // 减法
- dfs(nums, pos + 1, path - nums[pos]);
- }
- };
20、39. 组合总和
解法一:
- class Solution
- {
- int sum, aim;
- vector<int> path;
- vector<vector<int>> ret;
- public:
- vector<vector<int>> combinationSum(vector<int>& nums, int target)
- {
- aim = target;
- dfs(nums, 0, 0);
- return ret;
- }
-
- void dfs(vector<int>& nums, int pos, int sum)
- {
- if(sum == aim)
- {
- ret.push_back(path);
- return;
- }
-
- if(pos == nums.size() || sum > aim) return;
-
- for(int i = pos; i < nums.size(); i++)
- {
- path.push_back(nums[i]);
- dfs(nums, i, sum + nums[i]);
- path.pop_back();
- }
- }
- };
解法二:
- class Solution
- {
- int sum, aim;
- vector<int> path;
- vector<vector<int>> ret;
- public:
- vector<vector<int>> combinationSum(vector<int>& nums, int target)
- {
- aim = target;
- dfs(nums, 0, 0);
- return ret;
- }
-
- void dfs(vector<int>& nums, int pos, int sum)
- {
- if(sum == aim)
- {
- ret.push_back(path);
- return;
- }
-
- if(pos == nums.size() || sum > aim) return;
-
- // 枚举个数
- for(int k = 0; k * nums[pos] + sum <= aim; k++)
- {
- if(k) path.push_back(nums[pos]);
- dfs(nums, pos + 1, sum + k * nums[pos]);
- }
-
- // 恢复现场
- for(int k = 1; k * nums[pos] + sum <= aim; k++)
- {
- path.pop_back();
- }
- }
- };
- class Solution
- {
- vector<string> ret;
- string path;
- public:
- vector<string> letterCasePermutation(string s)
- {
- dfs(s, 0);
- return ret;
- }
-
- void dfs(string& s, int pos)
- {
- if(pos == s.size())
- {
- ret.push_back(path);
- return;
- }
-
- char ch = s[pos];
- path.push_back(ch);
- dfs(s, pos + 1);
- path.pop_back();
-
- if(ch < '0' || ch > '9')
- {
- char tmp = change(ch);
- path.push_back(tmp);
- dfs(s, pos + 1);
- path.pop_back();
- }
- }
-
- char change(char ch)
- {
- if(ch >= 'a' && ch <= 'z') ch -= 32;
- else ch += 32;
- return ch;
- }
- };
22、526. 优美的排列
- class Solution
- {
- bool check[16];
- int ret;
- public:
- int countArrangement(int n)
- {
- dfs(1, n);
- return ret;
- }
-
- void dfs(int pos, int n)
- {
- if(pos == n + 1)
- {
- ret++;
- return;
- }
-
- for(int i = 1; i <= n; i++)
- {
- if(!check[i] && (pos % i == 0 || i % pos == 0))
- {
- check[i] = true;
- dfs(pos + 1, n);
- check[i] = false; // 恢复现场
- }
- }
- }
- };
23、51. N 皇后?
- class Solution
- {
- bool checkCol[10], checkDig1[20], checkDig2[20];
- vector<vector<string>> ret;
- vector<string> path;
- int n;
- public:
- vector<vector<string>> solveNQueens(int _n)
- {
- n = _n;
- path.resize(n);
- for(int i = 0; i < n; i++)
- path[i].append(n, '.');
-
- dfs(0);
- return ret;
- }
-
- void dfs(int row)
- {
- if(row == n)
- {
- ret.push_back(path);
- return;
- }
-
- for(int col = 0; col < n; col++) // 尝试在这一行放皇后
- {
- // 剪枝
- if(!checkCol[col] && !checkDig1[row - col + n] && !checkDig2[row + col])
- {
- path[row][col] = 'Q';
- checkCol[col] = checkDig1[row - col + n] = checkDig2[row + col] = true;
- dfs(row + 1);
- // 恢复现场
- path[row][col] = '.';
- checkCol[col] = checkDig1[row - col + n] = checkDig2[row + col] = false;
- }
- }
- }
- };
24、36. 有效的数独
- class Solution
- {
- bool row[9][10];
- bool col[9][10];
- bool grid[3][3][10];
-
- public:
- bool isValidSudoku(vector<vector<char>>& board)
- {
- for(int i = 0; i < 9; i++)
- for(int j = 0; j < 9; j++)
- {
- if(board[i][j] != '.')
- {
- int num = board[i][j] - '0';
- // 是否是有效的
- if(row[i][num] || col[j][num] || grid[i / 3][j / 3][num])
- return false;
- row[i][num] = col[j][num] = grid[i / 3][j / 3][num] = true;
- }
- }
- return true;
- }
- };
25、37. 解数独
- class Solution
- {
- bool row[9][10], col[9][10], grid[3][3][10];
- public:
- void solveSudoku(vector<vector<char>>& board)
- {
- // 初始化
- for(int i = 0; i < 9; i++)
- {
- for(int j = 0; j < 9; j++)
- {
- if(board[i][j] != '.')
- {
- int num = board[i][j] - '0';
- row[i][num] = col[j][num] = grid[i / 3][j / 3][num] = true;
- }
- }
- }
- dfs(board);
- }
-
- bool dfs(vector<vector<char>>& board)
- {
- for(int i = 0; i < 9; i++)
- {
- for(int j = 0; j < 9; j++)
- {
- if(board[i][j] == '.')
- {
- // 填数
- for(int num = 1; num <= 9; num++)
- {
- if(!row[i][num] && !col[j][num] && !grid[i / 3][j / 3][num])
- {
- board[i][j] = '0' + num;
- row[i][num] = col[j][num] = grid[i / 3][j / 3][num] = true;
- if(dfs(board) == true) return true;
- // 恢复现场
- board[i][j] = '.';
- row[i][num] = col[j][num] = grid[i / 3][j / 3][num] = false;
- }
- }
- return false;
- }
- }
- }
- return true;
- }
- };
26、79. 单词搜索
- class Solution
- {
- bool vis[7][7];
- int m, n;
- public:
- bool exist(vector<vector<char>>& board, string word)
- {
- m = board.size(), n = board[0].size();
- for(int i = 0; i < m; i++)
- for(int j = 0; j < n; j++)
- {
- if(board[i][j] == word[0])
- {
- vis[i][j] = true;
- if(dfs(board, i, j, word, 1)) return true;
- vis[i][j] = false;
- }
- }
- return false;
- }
-
- int dx[4] = {0, 0, -1, 1};
- int dy[4] = {1, -1, 0, 0};
-
- bool dfs(vector<vector<char>>& board, int i, int j, string& word, int pos)
- {
- if(pos == word.size()) return true;
-
- // 向量的位置,定义上下左右四个位置
- for(int k = 0; k < 4; k++)
- {
- int x = i + dx[k], y = j + dy[k];
- if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && board[x][y] == word[pos])
- {
- vis[x][y] = true;
- if(dfs(board, x, y, word, pos + 1)) return true;
- vis[x][y] = false;
- }
- }
- return false;
- }
- };
27、1219. 黄金矿工
- class Solution
- {
- bool vis[16][16];
- int dx[4] = {0, 0, -1, 1};
- int dy[4] = {1, -1, 0, 0};
- int m, n, ret;
- public:
- int getMaximumGold(vector<vector<int>>& g)
- {
- m = g.size(), n = g[0].size();
- for(int i = 0; i < m; i++)
- for(int j = 0; j < n; j++)
- {
- if(g[i][j])
- {
- vis[i][j] = true;
- dfs(g, i, j, g[i][j]);
- vis[i][j] = false;
- }
- }
- return ret;
- }
-
- void dfs(vector<vector<int>>& g, int i, int j, int path)
- {
- ret = max(ret, path);
- for(int k = 0; k < 4; k++)
- {
- int x = i + dx[k], y = j + dy[k];
- if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && g[x][y])
- {
- vis[x][y] = true;
- dfs(g, x, y, path + g[x][y]);
- vis[x][y] = false;
- }
- }
- }
- };
- class Solution
- {
- bool vis[21][21];
- int dx[4] = {0, 0, -1, 1};
- int dy[4] = {1, -1, 0, 0};
- int ret;
- int m, n, step;
- public:
- int uniquePathsIII(vector<vector<int>>& grid)
- {
- m = grid.size(), n = grid[0].size();
-
- int bx = 0, by = 0;
- for(int i = 0; i < m; i++)
- for(int j = 0; j < n; j++)
- if(grid[i][j] == 0) step++;
- else if(grid[i][j] == 1)
- {
- bx = i;
- by = j;
- }
- step += 2;
- vis[bx][by] = true;
- dfs(grid, bx, by, 1);
- return ret;
- }
-
- void dfs(vector<vector<int>>& grid, int i, int j, int count)
- {
- if(grid[i][j] == 2)
- {
- if(count == step) // 判断是否合法
- ret++;
- return;
- }
-
- for(int k = 0; k < 4; k++)
- {
- int x = i + dx[k], y = j + dy[k];
- if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && grid[x][y] != -1)
- {
- vis[x][y] = true;
- dfs(grid, x, y, count + 1);
- vis[x][y] = false;
- }
- }
- }
- };
二、floodfill算法:
30、 733. 图像渲染
- class Solution
- {
- int m, n, prev;
- int dx[4] = {0, 0, -1, 1};
- int dy[4] = {1, -1, 0, 0};
- public:
- vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color)
- {
- if(image[sr][sc] == color) return image;
-
- m = image.size(), n = image[0].size();
- prev = image[sr][sc];
- dfs(image, sr, sc, color);
- return image;
- }
-
- void dfs(vector<vector<int>>& image, int i, int j, int color)
- {
- image[i][j] = color;
-
- for(int k = 0; k < 4; k++)
- {
- int x = i + dx[k], y = j + dy[k];
- if(x >= 0 && x < m && y >= 0 && y < n && image[x][y] == prev)
- {
- dfs(image, x, y, color);
- }
- }
- }
- };
31、200. 岛屿数量
- class Solution
- {
- vector<vector<bool>> vis;
- int dx[4] = {0, 0, -1, 1};
- int dy[4] = {1, -1, 0, 0};
- int m, n, ret;
- public:
- int numIslands(vector<vector<char>>& grid)
- {
- m = grid.size(), n = grid[0].size();
- vis = vector<vector<bool>>(m, vector<bool>(n));
-
- for(int i = 0; i < grid.size(); i++)
- for(int j = 0; j < grid[0].size(); j++)
- {
- if(!vis[i][j] && grid[i][j] == '1')
- {
- ret++;
- dfs(grid, i, j);
- }
- }
- return ret;
- }
-
- void dfs(vector<vector<char>>& grid, int i, int j)
- {
- vis[i][j] = true;
- for(int k = 0; k < 4; k++)
- {
- int x = i + dx[k], y = j + dy[k];
- if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && grid[x][y] == '1')
- {
- dfs(grid, x, y);
- }
- }
- }
- };
32、 695. 岛屿的最大面积
- class Solution
- {
- vector<vector<bool>> vis;
- int dx[4] = {0, 0, -1, 1};
- int dy[4] = {1, -1, 0, 0};
- int m, n, count;
- public:
- int maxAreaOfIsland(vector<vector<int>>& grid)
- {
- m = grid.size(), n = grid[0].size();
- vis = vector<vector<bool>>(m, vector<bool>(n));
-
- int ret = 0;
- for(int i = 0; i < grid.size(); i++)
- for(int j = 0; j < grid[0].size(); j++)
- {
- if(!vis[i][j] && grid[i][j] == 1)
- {
- count = 0;
- dfs(grid, i, j);
- ret = max(ret, count);
- }
- }
- return ret;
- }
-
- void dfs(vector<vector<int>>& grid, int i, int j)
- {
- count++;
- vis[i][j] = true;
- for(int k = 0; k < 4; k++)
- {
- int x = i + dx[k], y = j + dy[k];
- if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && grid[x][y] == 1)
- {
- dfs(grid, x, y);
- }
- }
- }
- };
33、 130. 被围绕的区域
- class Solution
- { // 正难则反
- int dx[4] = {0, 0, -1, 1};
- int dy[4] = {1, -1, 0, 0};
- int m, n;
- public:
- void solve(vector<vector<char>>& board)
- {
- // 1、把边界的0相连的连通块,全部修改成'.'
- m = board.size(), n = board[0].size();
- for(int j = 0; j < n; j++)
- {
- if(board[0][j] == 'O') dfs(board, 0, j);
- if(board[m - 1][j] == 'O') dfs(board, m - 1, j);
- }
-
- for(int i = 0; i < m; i++)
- {
- if(board[i][0] == 'O') dfs(board, i, 0);
- if(board[i][n - 1] == 'O') dfs(board, i, n - 1);
- }
-
- // 2、还原
- for(int i = 0; i < m; i++)
- for(int j = 0; j < n; j++)
- {
- if(board[i][j] == '.') board[i][j] = 'O';
- else if(board[i][j] == 'O') board[i][j] = 'X';
- }
- }
-
- void dfs(vector<vector<char>>& board, int i, int j)
- {
- board[i][j] = '.';
- for(int k = 0; k < 4; k++)
- {
- int x = i + dx[k], y = j + dy[k];
- if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'O')
- {
- dfs(board, x, y);
- }
- }
- }
- };
- class Solution
- {
- int dx[4] = {0, 0, -1, 1};
- int dy[4] = {1, -1, 0, 0};
- int m, n;
- public:
- vector<vector<int>> pacificAtlantic(vector<vector<int>>& h)
- {
- m = h.size(), n = h[0].size();
- vector<vector<bool>> pac(m, vector<bool>(n));
- vector<vector<bool>> atl(m, vector<bool>(n));
-
- // 1、先处理 pac 洋
- for(int j = 0; j < n; j++) dfs(h, 0, j, pac);
- for(int i = 0; i < m; i++) dfs(h, i, 0, pac);
-
- // 2、先处理 atl 洋
- for(int i = 0; i < m; i++) dfs(h, i, n - 1, atl);
- for(int j = 0; j < n; j++) dfs(h, m - 1, j, atl);
-
- vector<vector<int>> ret;
- for(int i = 0; i < m; i++)
- for(int j = 0; j < n; j++)
- if(pac[i][j] && atl[i][j])
- ret.push_back({i, j});
- return ret;
- }
-
- void dfs(vector<vector<int>>& h, int i, int j, vector<vector<bool>>& vis)
- {
- vis[i][j] = true;
- for(int k = 0; k < 4; k++)
- {
- int x = i + dx[k], y = j + dy[k];
- if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && h[x][y] >= h[i][j])
- {
- dfs(h, x, y, vis);
- }
- }
- }
- };
35、529. 扫雷游戏
- class Solution
- {
- int dx[8] = {0, 0, 1, -1, 1, 1, -1, -1};
- int dy[8] = {1, -1, 0, 0, 1, -1, 1, -1};
- int m, n;
-
- public:
- vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click)
- {
- m = board.size(), n = board[0].size();
- int x = click[0], y = click[1];
- if(board[x][y] == 'M') // 直接点到地雷
- {
- board[x][y] = 'X';
- return board;
- }
- dfs(board, x, y);
- return board;
- }
-
- void dfs(vector<vector<char>>& board, int i, int j)
- {
- // 统计一下周围的地雷个数
- int count = 0;
- for(int k = 0; k < 8; k++)
- {
- int x = i + dx[k], y = j + dy[k];
- if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'M')
- {
- count++;
- }
- }
- if(count) // 周围有地雷
- {
- board[i][j] = count + '0';
- return;
- }
- else // 周围没有地雷
- {
- board[i][j] = 'B';
- for(int k = 0; k < 8; k++)
- {
- int x = i + dx[k], y = j + dy[k];
- if(x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'E')
- {
- dfs(board, x, y);
- }
- }
- }
- }
- };
三、记忆化搜索:
37、509. 斐波那契数
解法一:递归 O(2^N)
解法二:记忆化搜索 O(N)
①是什么:带备忘录的递归。
②怎么实现:添加一个备忘录<可变参数,返回值>,把结果放到备忘录里面,在每次进入递归的时候向备忘录里查找一下。
- class Solution
- {
- int memo[31]; // memory
- public:
- int fib(int n)
- {
- // 初始化
- memset(memo, -1, sizeof memo);
- return dfs(n);
- }
-
- int dfs(int n)
- {
- // 往备忘录里查找一下
- if(memo[n] != -1) // 剪枝
- {
- return memo[n];
- }
-
- if(n == 0 || n == 1)
- {
- memo[n] = n; // 返回之前放进备忘录里面
- return n;
- }
-
- memo[n] = dfs(n - 1) + dfs(n - 2); // 返回之前放进备忘录里面
- return memo[n];
- }
- };
解法三:
①确定状态表示(dfs函数的含义);
②推导状态转移方程(dfs的函数体);
③初始化(dfs函数的递归出口);
④确定填表顺序(填写备忘录的顺序);
⑤确定返回值(主函数是如何调用dfs的)。
- class Solution
- {
- int dp[31];
- public:
- int fib(int n)
- {
- // 动态规划
- dp[0] = 0, dp[1] = 1;
- for(int i = 2; i <= n; i++)
- dp[i] = dp[i - 1] + dp [i - 2];
- return dp[n];
- }
- };
总结:动态规划和记忆化搜索的本质:
①暴力解法(暴搜)。
②对暴力解法的优化:把已经计算过的值存起来。
问题:
①所有的递归(暴搜、深搜),都能改成记忆化搜索吗?
不是的,只有在递归的过程中,出现了大量的完全相同的问题时,才能用记忆化搜索的方式优化。
②带备忘录的递归 vs 带备忘录的动态规划 vs 记忆化搜索?
都是一回事。
③自顶向下 vs 自底向上?
记忆化搜索:自顶向下。
常规动态规划:自底向上。
④暴搜->记忆化搜索->动态规划 vs 常规动态规划?
80%可以用前者的思考方式,但有些题用暴搜的时间成本太高了(暴搜只是为我们确定状态表示提供方向)。
38、62. 不同路径
解法一:暴搜->记忆化搜索:
- class Solution
- {
- public:
- int uniquePaths(int m, int n)
- {
- // 记忆化搜索
- vector<vector<int>> memo(m + 1, vector<int>(n + 1));
- return dfs(m, n, memo);
- }
-
- int dfs(int i, int j, vector<vector<int>>& memo)
- {
- if(memo[i][j] != 0) return memo[i][j];
-
- if(i == 0 || j == 0) return 0;
- if(i == 1 && j == 1)
- {
- memo[i][j] = 1;
- return 1;
- }
-
- memo[i][j] = dfs(i - 1, j, memo) + dfs(i, j - 1, memo);
- return memo[i][j];
- }
- };
解法二:动态规划:
- class Solution
- {
- public:
- int uniquePaths(int m, int n)
- {
- // 1、创建dp表
- vector<vector<int>> dp(m + 1, vector<int>(n + 1));
-
- // 2、初始化
- dp[0][1] = 1;
-
- // 3、填表
- for(int i = 1; i <= m; i++)
- {
- for(int j = 1; j <= n; j++)
- {
- dp[i][j] = dp[i-1][j] + dp[i][j-1];
- }
- }
-
- // 4、返回值
- return dp[m][n];
- }
- };
39、300. 最长递增子序列
解法一:暴搜->记忆化搜索:
- class Solution
- {
- public:
- int lengthOfLIS(vector<int>& nums)
- {
- int n = nums.size();
- vector<int> memo(n);
-
- int ret = 0;
- for(int i = 0; i < nums.size(); i++)
- ret = max(ret, dfs(i, nums, memo));
- return ret;
- }
-
- int dfs(int pos, vector<int>& nums, vector<int>& memo)
- {
- if(memo[pos] != 0) return memo[pos];
- int ret = 1;
- for(int i = pos + 1; i < nums.size(); i++)
- {
- if(nums[i] > nums[pos])
- {
- ret = max(ret, dfs(i, nums, memo) + 1);
- }
- }
- memo[pos] = ret;
- return memo[pos];
- }
- };
解法二:动态规划:
- class Solution
- {
- int ret = 0;
- int n = nums.size();
- public:
- int lengthOfLIS(vector<int>& nums)
- {
- // 动态规划
- vector<int> dp(n, 1);
-
- // 填表顺序:从后往前(以i为首的最长递增子序列)
- for(int i = n - 1; i >= 0; i--)
- {
- for(int j = i + 1; j < n; j++)
- {
- if(nums[j] > nums[i])
- {
- dp[i] = max(dp[i], dp[j] + 1);
- }
- }
- ret = max(ret, dp[i]);
- }
- return ret;
- }
- };
40、375. 猜数字大小 II?
- class Solution
- {
- int memo[201][201];
- public:
- int getMoneyAmount(int n)
- {
- return dfs(1, n);
- }
-
- int dfs(int left, int right)
- {
- if(left >= right) return 0;
- if(memo[left][right] != 0) return memo[left][right];
-
- int ret = INT_MAX;
- for(int head = left; head <= right; head++) // 选择头结点·
- {
- int x = dfs(left, head - 1);
- int y = dfs(head + 1, right);
- ret = min(ret, head + max(x, y));
- }
- memo[left][right] = ret;
- return memo[left][right];
- }
- };
- class Solution
- {
- int dx[4] = {0, 0, -1, 1};
- int dy[4] = {1, -1, 0, 0};
- int m, n;
- int memo[201][201];
-
- public:
- int longestIncreasingPath(vector<vector<int>>& matrix)
- {
- int ret = 0;
- m = matrix.size(), n = matrix[0].size();
-
- for(int i = 0; i < m; i++)
- for(int j = 0; j < n; j++)
- {
- ret = max(ret, dfs(matrix, i, j));
- }
- return ret;
- }
-
- int dfs(vector<vector<int>>& matrix, int i, int j)
- {
- if(memo[i][j] != 0) return memo[i][j];
-
- int ret = 1;
- for(int k = 0; k < 4; k++)
- {
- int x = i + dx[k], y = j + dy[k];
- if(x >= 0 && x < m && y >= 0 && y < n && matrix[x][y] > matrix[i][j])
- {
- ret = max(ret, dfs(matrix, x, y) + 1);
- }
- }
- memo[i][j] = ret;
- return memo[i][j];
- }
- };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。