题目描述 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。 必须原地修改,只允许使用额外常数空间。 以下是一些例子,输入位于左侧列,其相应输出位于右侧列。 题解: c++版 python版 题目描述 示例 1: 输入: “(()” 示例 2: 输入: “)()())” 题解: c++版 python版 题目描述 你的算法时间复杂度必须是 O(log n) 级别。 如果数组中不存在目标值,返回 [-1, -1]。 示例 1: 输入: nums = [5,7,7,8,8,10], target = 8 示例 2: 输入: nums = [5,7,7,8,8,10], target = 6 题解; c++版 python版 题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 你可以假设数组中无重复元素。 示例 1: 输入: [1,3,5,6], 5 示例 2: 输入: [1,3,5,6], 2 示例 3: 输入: [1,3,5,6], 7 示例 4: 输入: [1,3,5,6], 0 题解: c++版 python版 题目描述 判断一个 9×9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 数独部分空格内已填入了数字,空白格用 ‘.’ 表示。 示例 1: 输入: 示例 2: 输入: 说明: 题解: c++版 python版 题目描述 编写一个程序,通过已填充的空格来解决数独问题。 一个数独的解法需遵循如下规则: 一个数独。 提示 题解 c++版 python版 题目描述 给定一个正整数 n(1 ≤ n ≤ 30),输出外观数列的第 n 项。 注意:整数序列中的每一项将表示为一个字符串。 「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。前五项如下: 第一项是数字 1 描述前一项,这个数是 1 即 “一个 1 ”,记作 11 描述前一项,这个数是 11 即 “两个 1 ” ,记作 21 描述前一项,这个数是 21 即 “一个 2 一个 1 ” ,记作 1211 描述前一项,这个数是 1211 即 “一个 1 一个 2 两个 1 ” ,记作 111221 示例 1: 输入: 1 示例 2: 输入: 4 题解: c++版 python版 题目描述 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。 说明: 示例 1: 输入:candidates = [2,3,6,7], target = 7, 示例 2: 输入:candidates = [2,3,5], target = 8, 提示: 题解: c++版 python版 题目描述 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。 示例 1: 输入: candidates = [10,1,2,7,6,1,5], target = 8, 输入: candidates = [2,5,2,1,2], target = 5, 题解: c++版 python文章目录
31. 下一个排列
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
找规律O(n):
我们可以这样来分析:
我们希望 下一个数比当前数大,这样才满足“下一个排列”的定义。因此只需要将后面的「大数」与前面的「小数」交换,就能得到一个更大的数。
比如 123456
,将 5
和 6
交换就能得到一个更大的数 123465
。
我们还希望 下一个数增加的幅度尽可能的小,这样才满足“下一个排列与当前排列紧邻“的要求。为了满足这个要求,我们需要:
在尽可能靠右的低位进行交换,需要从后向前查找
将一个 尽可能小的「大数」 与前面的「小数」交换。比如 123465
,下一个排列应该把 5
和 4
交换而不是把 6
和 4
交换
将「大数」换到前面后,需要将「大数」后面的所有数 重置为升序,升序排列就是最小的排列。以 123465
为例:首先按照上一步,交换 5
和 4
,
得到 123564
;然后需要将 5
之后的数重置为升序,得到 123546
。显然 123546
比 123564
更小,123546
就是 123465
的下一个排列。class Solution { public: void nextPermutation(vector<int>& nums) { int i = nums.size() - 1; while(i > 0 && nums[i - 1] >= nums[i])i--; if(i == 0) sort(nums.begin(),nums.end()); else{ int t = i; while(t < nums.size() && nums[t] > nums[i - 1])t++; swap(nums[t - 1], nums[i - 1]); reverse(nums.begin() + i, nums.end()); } } };
class Solution: def nextPermutation(self, nums: List[int]) -> None: """ Do not return anything, modify nums in-place instead. """ i = len(nums) - 1 while i > 0 and nums[i - 1] >= nums[i]: i -= 1 if i == 0: nums.sort() else: t = i while t < len(nums) and nums[t] > nums[i - 1]: t += 1 nums[i - 1], nums[t - 1] = nums[t - 1], nums[i - 1] nums[i:len(nums) + 1] = nums[i:len(nums) + 1][::-1]
2. 最长有效括号
给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
输出: 2
解释: 最长有效括号子串为 “()”
输出: 4
解释: 最长有效括号子串为 “()()”
二分O(logn):
对于旋转数组 nums = [4,5,6,7,0,1,2]
首先根据 nums[0] 与 target 的关系判断 target 是在左段还是右段。
例如 target = 5, 目标值在左半段,因此在 [4, 5, 6, 7, inf, inf, inf] 这个有序数组里找就行了;
例如 target = 1, 目标值在右半段,因此在 [-inf, -inf, -inf, -inf, 0, 1, 2] 这个有序数组里找就行了。class Solution { public: int longestValidParentheses(string s) { int arr[100010] = {0}; int t = 0; int ans = 0; for(int i = 0; i < s.size(); i++){ if(s[i] == '(') arr[++t] = i; else{ if(t == 0) arr[++t] = i; else if(s[arr[t]] == '(') t--; else arr[++t] = i; } if(t == 0) ans = i + 1; else ans = max(ans, i - arr[t]); } return ans; } };
class Solution: def longestValidParentheses(self, s: str) -> int: l = [0 for _ in range(100010)] t = 0 ans = 0 for i in range(0, len(s)): if s[i] == '(': t += 1 l[t] = i else: if t > 0 and s[l[t]] == '(': t -= 1 else: t += 1 l[t] = i if t == 0: ans = i + 1 else: ans = max(ans, i - l[t]) return ans
34. 在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
输出: [3,4]
输出: [-1,-1]
二分模板题O(logn)class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { vector<int> a, b; a.push_back(-1); a.push_back(-1); if(nums.size() == 0) return a; int left = 0, right = nums.size() - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] < target) left = mid + 1; else if (nums[mid] >= target) right = mid - 1; } // 最后要检查 left 越界的情况 if (left >= nums.size() || nums[left] != target) return a; b.push_back(left); left = 0, right = nums.size() - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] <= target) left = mid + 1; else if (nums[mid] > target) right = mid - 1; } // 最后要检查 left 越界的情况 if (right < 0 || nums[right] != target) return a; b.push_back(right); return b; } };
class Solution: def searchRange(self, nums: List[int], target: int) -> List[int]: if not nums: return [-1,-1] n = len(nums) l, r = 0, n - 1 while l <= r: mid = (l + r) // 2 if nums[mid] >= target: r = mid - 1 else: l = mid + 1 if l >= n or nums[l] != target: return [-1, -1] ans1 = l l, r = 0, n - 1 while l <= r: mid = (l + r) // 2 if nums[mid] <= target: l = mid + 1 else: r = mid - 1 if r < 0 or nums[r] != target: return [-1, -1] ans2 = r return [ans1, ans2]
35. 搜索插入位置
输出: 2
输出: 1
输出: 4
输出: 0
二分模板题O(logn)class Solution { public: int searchInsert(vector<int>& nums, int target) { int l = 0, r = nums.size() - 1; while(l <= r){ int mid = (l + r) / 2; if(nums[mid] == target) return mid; if(nums[mid] > target) r = mid - 1; else l = mid + 1; } return r + 1; } };
class Solution: def searchInsert(self, nums: List[int], target: int) -> int: n = len(nums) l, r = 0, n - 1 while l <= r: mid = (l + r) // 2 if nums[mid] == target: return mid if nums[mid] > target: r = mid - 1 else: l = mid + 1 return r + 1
36. 有效的数独
上图是一个部分填充的有效的数独。
[
[“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”]
]
输出: true
[
[“8”,“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”]
]
输出: false
解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。
但由于位于左上角的 3×3 宫内有两个 8 存在, 因此这个数独是无效的。
1.位运算判重
分别使用一个整型数组记录每行、每列和每个九宫格内数字的存在情况。
位运算可以极大的简化判断,提高效率,具体看代码。
2.二维布尔数组判断
原理跟位运算一样class Solution { public: bool isValidSudoku(vector<vector<char>>& board) { int N = 9; int r[N], c[N], cell[3][3]; for(int i = 0; i < N; i++) r[i] = c[i] = (1 << N) - 1; for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) cell[i][j] = (1 << N) - 1; for(int i = 0; i < N; i++){ for(int j = 0; j < N; j++){ if(board[i][j] != '.'){ int a = i / 3; int b = j / 3; int t = board[i][j] - '1'; if(!(r[i] & 1 << t) || !(c[j] & 1 << t) || !(cell[a][b] & 1 << t)) return false; r[i] -= 1 << t; c[j] -= 1 << t; cell[a][b] -= 1 << t; } } } return true; } };
class Solution: def isValidSudoku(self, board): """ :type board: List[List[str]] :rtype: bool """ # init data N = 9 row = [{} for _ in range(N)] col = [{} for _ in range(N)] cell = [{} for _ in range(N)] for i in range(N): for j in range(N): ce_index = i // 3 * 3 + j // 3 if board[i][j] != '.': t = int(board[i][j]) if t in row[i] or t in col[j] or t in cell[ce_index]: return False row[i][t] = 1 col[j][t] = 1 cell[ce_index][t] = 1 return True
37. 解数独
空白格用 ‘.’ 表示。
(递归回溯):
1.首先预处理出 col、row 和 squ 数组。
2.从 (0,0) 位置开始尝试并递归。遇到 . 时,枚举可以填充的数字,然后判重并加入 col、row 和 squ 数组中。
3.如果成功到达结尾,则返回 true,告知递归可以终止。class Solution { public: bool row[9][9], col[9][9], cell[3][3][9]; void solveSudoku(vector<vector<char>>& board) { memset(row, false, sizeof row); memset(col, false, sizeof col); memset(cell, false, sizeof cell); for(int i = 0; i < 9; i++) for(int j = 0; j < 9; j++) if(board[i][j] != '.'){ int t = board[i][j] - '1'; row[i][t] = col[j][t] = cell[i / 3][j / 3][t] = true; } dfs(board, 0, 0); } bool dfs(vector<vector<char>>& board, int x, int y){ if(y == 9) x += 1, y = 0; if(x == 9) return true; if(board[x][y] != '.') return dfs(board, x, y + 1); for(int i = 0; i < 9; i++){ if(!row[x][i] && !col[y][i] && !cell[x / 3][y / 3][i]){ board[x][y] = i + '1'; row[x][i] = col[y][i] = cell[x / 3][y / 3][i] = true; if(dfs(board, x, y + 1)) return true; board[x][y] = '.'; row[x][i] = col[y][i] = cell[x / 3][y / 3][i] = false; } } return false; } };
class Solution: def solveSudoku(self, board: List[List[str]]) -> None: """ Do not return anything, modify board in-place instead. """ row = [[False for _ in range(9)] for _ in range(9)] col = [[False for _ in range(9)] for _ in range(9)] cell = [[False for _ in range(9)] for _ in range(9)] for i in range(9): for j in range(9): if board[i][j] != '.': t = int(board[i][j]) - 1 row[i][t] = col[j][t] = cell[i // 3 * 3 + j // 3][t] = True; def dfs(board, x, y): if y == 9: x += 1; y = 0 if x == 9: return True if board[x][y] != '.': return dfs(board, x, y + 1) for i in range(9): if not row[x][i] and not col[y][i] and not cell[x // 3 * 3 + y // 3][i]: board[x][y] = str(i + 1) row[x][i] = col[y][i] = cell[x // 3 * 3 + y // 3][i] = True if(dfs(board, x, y + 1)): return True board[x][y] = '.' row[x][i] = col[y][i] = cell[x // 3 * 3 + y // 3][i] = False return False dfs(board, 0, 0)
38. 外观数列
1. 1 2. 11 3. 21 4. 1211 5. 111221
输出: “1”
解释:这是一个基本样例。
输出: “1211”
解释:当 n = 3 时,序列是 “21”,其中我们有 “2” 和 “1” 两组,“2” 可以读作 “12”,也就是出现频次 = 1 而 值 = 2;类似 “1” 可以读作 “11”。所以答案是 “12” 和 “11” 组合在一起,也就是 “1211”。
(模拟) O(n2)
直接按照从 2 到 n 的顺序生成字符串,即每次找连续相同的数字段,合并。class Solution { public: string countAndSay(int n) { string s = "1"; for (int i = 0; i < n - 1; i ++ ) { string t; for (int j = 0; j < s.size();) { int k = j + 1; while (k < s.size() && s[k] == s[j]) k ++ ; t += to_string(k - j) + s[j]; j = k; } s = t; } return s; } };
class Solution: def countAndSay(self, n: int) -> str: s = '1' for i in range(n - 1): j = 0 t = "" while j < len(s): k = j + 1 while k < len(s) and s[k] == s[j]: k += 1 t += str(k - j) + s[j] j = k s = t return s
39. 组合总和
所求解集为:
[
[7],
[2,2,3]
]
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
(递归枚举)
在每一层搜索中,枚举这个数字添加几次。
搜索的终止条件是层数超过的数组的长度或者当前数字组合等于目标值。
剪枝:可以先将数组从小到大排序,搜索中如果 sum != target 并且 sum+candidates[i] > target,
则可以直接终止之后的递归,因为之后的数字都会比 candidates[i] 大,不会再产生答案。class Solution { public: vector<vector<int>> ans; vector<int> path; vector<vector<int>> combinationSum(vector<int>& candidates, int target) { dfs(candidates, 0, target); return ans; } void dfs(vector<int>& candidates, int cur, int target){ if(target == 0){ ans.push_back(path); return ; } if(target < 0) return ; if(cur == candidates.size()) return ; for(int i = 0; i * candidates[cur] <= target; i++){ dfs(candidates, cur + 1, target - i * candidates[cur]); path.push_back(candidates[cur]); } for(int i = 0; i * candidates[cur] <= target; i++) path.pop_back(); } };
class Solution: def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: ans = [] path = [] def dfs(c, cur, target): if target == 0: ans.append(path[:]) return if target < 0: return if cur == len(c): return i = 0 while(i * c[cur] <= target): dfs(c, cur + 1, target - i * c[cur]) path.append(c[cur]) i += 1 i = 0 while(i * c[cur] <= target): path.pop() i += 1 dfs(candidates, 0, target) return ans
40. 组合总和 II
**
**说明:
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
所求解集为:
[
[1,2,2],
[5]
]
递归搜索:
排序,对于每层搜索,判断当前数字重复的次数,保证搜索下一层的数字和当前数字不一样class Solution { public: vector<vector<int>> ans; vector<int> path; vector<vector<int>> combinationSum2(vector<int>& c, int target) { sort(c.begin(), c.end()); dfs(c, 0, target); return ans; } void dfs(vector<int>& c, int u, int target) { if (target == 0) { ans.push_back(path); return; } if (u == c.size()) return; int k = u + 1; while (k < c.size() && c[k] == c[u]) k ++ ; int cnt = k - u; for (int i = 0; c[u] * i <= target && i <= cnt; i ++ ) { dfs(c, k, target - c[u] * i); path.push_back(c[u]); } for (int i = 0; c[u] * i <= target && i <= cnt; i ++ ) { path.pop_back(); } } };
class Solution: def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]: ans = [] path = [] candidates.sort() def dfs(c, cur, target): if target == 0: ans.append(path[:]) return if cur == len(c): return if target < 0: return k = cur + 1 while k < len(c) and c[k] == c[cur]: k += 1 cnt = k - cur i = 0 while i <= cnt and i * c[cur] <= target: dfs(c, k, target - i * c[cur]) path.append(c[cur]) i += 1 i = 0 while i <= cnt and i * c[cur] <= target: path.pop() i += 1 dfs(candidates, 0, target) return ans
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算