8. 字符串转换整数 (atoi)(中等)
【分类】:模拟、正则表达式
【题解】:
解法1:直接模拟,但是在判断INT_MAX和INT_MIN上需要注意,因为直接判断会超出范围,所以可以将式子转换一下,本来是num * 10 + str[i] - '0' > MAX,可以转换为(MAX - (stri[i] - '0')) / 10 < num。
解法2:不得不说正则表达式真的牛逼啊啊啊啊!!!
'^[+-]?d+', s.lstrip()
让我们来分析一下这个关键部分!
^x:表示匹配以字符串x为开头的字符串
[+-]?:匹配+或-或者什么也没有(?表示将前面的字符匹配0或1次)
d:表示数字
+:表示前面的字符一次或无数次
s.lstrip(a):将字符串前面连续的a字符去除,默认为‘ ’
肯定有人要问最前面的*是什么意思了!!这个是解包,可以将findall返回的列表组成一个字符串。
【代码】:
C++(解法1):
1 class Solution { 2 public: 3 int myAtoi(string str) { 4 int i = 0, f = 0; 5 for (i = 0; i < str.size() && str[i] == ' '; i++); 6 if (str[i] == '-')f = -1, i++; 7 else if (str[i] == '+') f = 1, i++; 8 else if(isdigit(str[i]))f = 1; 9 if (f == 0)return 0; 10 int num = 0, f2 = 0; 11 int MAX = 2147483647, MIN = -2147483648; 12 for (; i < str.size() && isdigit(str[i]); i++) 13 { 14 if (num > ((MAX - (str[i] - '0')) / 10 )) 15 { 16 if (f == 1)return MAX; 17 else return MIN; 18 } 19 num = num * 10 + (str[i] - '0'); 20 } 21 if (f == 1)return num; 22 else return -num; 23 } 24 };
Python3(解法2):
1 class Solution: 2 def myAtoi(self, s: str) -> int: 3 return max(min(int(*re.findall('^[+-]?d+', s.lstrip())), 2**31 - 1), -2**31)
11. 盛最多水的容器(中等)
【分类】:双指针
【题解】:将指针l、r分别位于两端,比较两端元素大小,假如说左端大,那么易得以右端为端点已经取到了最大值(因为元素间距离不能再大了),我们接下来可以看看以左端为端点还能不能更大,所以要把右指针往左移,此时如果右端大,那么以左端为端点已经取得了最大值,依次类推。
【代码】:
C++:
1 class Solution { 2 public: 3 int maxArea(vector<int>& height) { 4 int ans = 0, l = 0, r = height.size() - 1; 5 while(l <= r) 6 { 7 ans = max(ans, min(height[l], height[r]) * (r - l)); 8 if (height[l] > height[r])r--; 9 else l++; 10 } 11 return ans; 12 } 13 };
Python3:
1 class Solution: 2 def maxArea(self, height: List[int]) -> int: 3 ans = 0 4 l = 0 5 r = len(height) - 1 6 while l <= r: 7 ans = max(ans, min(height[l], height[r]) * (r - l)) 8 if (height[l] > height[r]): r -= 1 9 else: l += 1 10 return ans
22. 括号生成(中等)
【分类】:dfs、动态规划
【题解】:
解法1:回溯法,l为剩余左括号数量,r为剩余右括号数量,先考虑递归出口,也就是l=0&r=0的时候return(没有剩余括号啦)。然后只要l还有剩余我们就可以一直递归下去,那么右括号什么情况可以递归呢,必须当r > l时才可以,比如n=2我现在是(),后面肯定不能再加)啦。
解法2:考虑n个括号的情况可以由n-1个括号的情况得到,假设第n个括号的左括号在最左,那么n个括号的情况就是这样了()a,(a),a就是前n-1个括号的情况。所以也可以统一为(p)q,p = [0, n - 1],q = n - 1 - p即可涵盖上述情况。
【代码】:
C++(解法1):
1 class Solution { 2 public: 3 vector<string>ans; 4 vector<string> generateParenthesis(int n) { 5 dfs("", n, n); 6 return ans; 7 } 8 void dfs(string s, int l, int r) 9 { 10 if (l == 0 && r == 0) 11 { 12 ans.push_back(s); 13 return; 14 } 15 if (l > 0) 16 dfs(s + "(", l - 1, r); 17 if (r > l) 18 dfs(s + ")", l, r - 1); 19 return; 20 } 21 };
Python3(解法2):
1 class Solution: 2 def generateParenthesis(self, n: int) -> List[str]: 3 dp = [] 4 dp.append([""]) 5 for i in range(1, n + 1): 6 cur = [] 7 for j in range(i): 8 l = dp[j] 9 r = dp[i - 1 -j] 10 for ll in l: 11 for rr in r: 12 s = "(" + ll + ")" + rr 13 cur.append(s) 14 dp.append(cur) 15 return dp[n]
55. 跳跃游戏(中等)
【分类】:贪心
【题解】:
解法1:因为每个位置除0外最小能跳的距离为1,实际上只要考虑每个0的位置能否跳过即可,所以每当遍历到0的时候,再往前遍历查找是否有一个位置能够跳过0,只要能跳过所有的0位置,就一定能跳到终点。
解法2:维护一个当前可以跳到的最大距离值。
【代码】:
C++(解法1):
1 class Solution { 2 public: 3 bool canJump(vector<int>& nums) { 4 for (int i = 0; i < nums.size() - 1; i++) 5 { 6 if (nums[i] == 0) 7 { 8 int f = 0; 9 int t = i + 1, j = i - 1; 10 while(j >= 0) 11 { 12 if (nums[j] >= t - j) 13 { 14 f = 1; 15 break; 16 } 17 j--; 18 } 19 if (!f)return false; 20 } 21 } 22 return true; 23 } 24 };
Python3(解法2):
1 class Solution: 2 def canJump(self, nums: List[int]) -> bool: 3 rightmost = 0 4 for i in range(len(nums)): 5 if rightmost >= i: 6 rightmost = max(rightmost, i + nums[i]) 7 else: 8 return False 9 return True
56. 合并区间(中等)
【分类】:贪心
【题解】:每个区间按照左端点进行排序,然后遍历所有区间,当下一个区间的左端点大于当前区间的右端点说明这段区间不重合,反之说明重合,所以更新重合区间的右端点。
【代码】:
C++:
1 struct Node{ 2 int x, y; 3 }; 4 class Solution { 5 public: 6 static bool cmp(Node a, Node b) 7 { 8 return a.x != b.x ? a.x < b.x : a.y < b.y; 9 } 10 vector<vector<int>> merge(vector<vector<int>>& intervals) { 11 vector<Node>v; 12 vector<vector<int> > ans; 13 for (int i = 0; i < intervals.size(); i++) 14 v.push_back({intervals[i][0], intervals[i][1]}); 15 if (v.size() == 0)return ans; 16 sort(v.begin(), v.end(), cmp); 17 int l = v[0].x, r = v[0].y; 18 for (int i = 1; i < v.size(); i++) 19 { 20 if (v[i].x <= r) r = max(v[i].y, r); 21 else 22 { 23 vector<int>t; 24 t.push_back(l); 25 t.push_back(r); 26 ans.push_back(t); 27 l = v[i].x; 28 r = v[i].y; 29 } 30 } 31 vector<int>t; 32 t.push_back(l); 33 t.push_back(r); 34 ans.push_back(t); 35 return ans; 36 } 37 };
Python3:
1 class Solution: 2 def merge(self, intervals: List[List[int]]) -> List[List[int]]: 3 if len(intervals) == 0: 4 return [] 5 res = [] 6 intervals.sort(key=lambda x: x[0]) 7 for inter in intervals: 8 if len(res) == 0 or res[-1][1] < inter[0]: 9 res.append(inter) 10 else: 11 res[-1][1] = max(res[-1][1], inter[1]) 12 return res
151. 翻转字符串里的单词(中等)
【分类】:字符串
【题解】:这种字符串的题用Python简直不要方便太多!!C++的话根据题意老老实实模拟就好啦。
【代码】:
C++:
1 class Solution { 2 public: 3 string reverseWords(string s) { 4 vector<string>v; 5 string ss = ""; 6 for (int i = 0; i < s.size(); i++) 7 { 8 if (s[i] != ' ')ss = ss + s[i]; 9 else 10 { 11 if (ss != "") 12 { 13 v.push_back(ss); 14 ss = ""; 15 } 16 } 17 } 18 if (ss != "")v.push_back(ss); 19 if (v.size() == 0)return ""; 20 ss = ""; 21 reverse(v.begin(), v.end()); 22 for (int i = 0; i < v.size() - 1; i++) 23 ss = ss + v[i] + " "; 24 ss = ss + v[v.size() - 1]; 25 return ss; 26 } 27 };
Python3:
1 class Solution: 2 def reverseWords(self, s: str) -> str: 3 ls = s.split(' ') # 按空格分隔单词 4 ls = list(filter(None, ls)) # 去除列表中的空字符串 5 ls.reverse() # 将列表倒序 6 ans = " ".join(ls) 7 return ans
199. 二叉树的右视图(中等)
【分类】:dfs、bfs、二叉树
【题解】:
解法1:bfs,维护一个数组d,d[i]表示深度为i的节点值,因为bfs是从左往右层序遍历,所以遍历过程中每个深度最后保存的值就是右视图看过去的值。
解法2:dfs,先遍历右子树,更新在每一层最先出现的元素即可。
【代码】:
C++(解法1):
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 int ans[10005]; 13 vector<int> rightSideView(TreeNode* root) { 14 queue<TreeNode*>q; 15 queue<int>d; 16 vector<int>v; 17 if (root == NULL)return v; 18 q.push(root); 19 d.push(0); 20 int maxdepth = 0; 21 while(!q.empty()) 22 { 23 TreeNode* t = q.front(); 24 q.pop(); 25 int dd = d.front(); 26 d.pop(); 27 ans[dd] = t->val; 28 maxdepth = max(maxdepth, dd); 29 if (t->left != NULL) 30 { 31 q.push(t->left); 32 d.push(dd + 1); 33 } 34 if (t->right != NULL) 35 { 36 q.push(t->right); 37 d.push(dd + 1); 38 } 39 } 40 for(int i = 0; i <= maxdepth; i++) 41 v.push_back(ans[i]); 42 return v; 43 } 44 };
Python3(解法2):
1 # Definition for a binary tree node. 2 # class TreeNode: 3 # def __init__(self, x): 4 # self.val = x 5 # self.left = None 6 # self.right = None 7 8 class Solution: 9 def dfs(self, root, depth): 10 if root == None: return 11 if depth > len(self.ans): 12 self.ans.append(root.val) 13 self.dfs(root.right, depth + 1) 14 self.dfs(root.left, depth + 1) 15 def rightSideView(self, root: TreeNode) -> List[int]: 16 self.ans = [] 17 self.dfs(root, 1) 18 return self.ans
200. 岛屿数量(中等)
【分类】:dfs、bfs
【题解】:算是比较基础的搜索题吧,只写了dfs。一定要看清楚题目是字符啊!!我一直以为是数字,被坑了好久。
【代码】:
C++:
1 class Solution { 2 public: 3 int dirx[4] = {0, 0, 1, -1}; 4 int diry[4] = {1, -1, 0, 0}; 5 void dfs(vector<vector<char>>& grid, int x, int y, int n, int m) 6 { 7 if (x < 0 || x >= n || y < 0 || y >= m || grid[x][y] == '0') 8 return; 9 grid[x][y] = '0'; 10 for(int i = 0; i < 4; i++) 11 dfs(grid, x + dirx[i], y + diry[i], n, m); 12 return; 13 } 14 int numIslands(vector<vector<char>>& grid) { 15 int n = grid.size(); 16 if (n == 0)return 0; 17 int m = grid[0].size(); 18 int ans = 0; 19 for (int i = 0; i < n; i++) 20 { 21 for (int j = 0; j < m; j++) 22 { 23 if (grid[i][j] == '1') 24 { 25 ans++; 26 dfs(grid, i, j, n, m); 27 } 28 } 29 } 30 return ans; 31 } 32 };
Python3:
1 class Solution: 2 def __init__(self): 3 self.dire = [(0, 1), (0, -1), (1, 0), (-1, 0)] 4 def dfs(self, grid, x, y, n, m): 5 if x < 0 or x >= n or y < 0 or y >= m or grid[x][y] == '0': 6 return 7 grid[x][y] = '0' 8 for d in self.dire: 9 self.dfs(grid, x + d[0], y + d[1], n, m) 10 def numIslands(self, grid: List[List[str]]) -> int: 11 n = len(grid) 12 if n == 0: return 0 13 m = len(grid[0]) 14 ans = 0 15 for i in range(n): 16 for j in range(m): 17 if grid[i][j] == '1': 18 ans += 1 19 self.dfs(grid, i, j, n, m) 20 return ans;
289. 生命游戏(中等)
【分类】:模拟、位运算
【题解】:
解法1:直接模拟,因为要求必须同时进行,所以只要将更新后的状态赋值给另一个数组,等更新完后再赋值回去就可以啦。
解法2:位运算。这个操作还是挺有意思的,反正我想不出来。现在我们用二进制表示每个格子细胞的状态(低位为之前的状态,高位为后来的状态):
(0)00:表示刚开始死的,后来还是死的
(1)01:表示刚开始活的,后来死了
(2)10:表示刚开始死的,后来活了
(3)11:表示刚开始活的,后来还是活的
然后分析一下条件可以发现:
1、当细胞是活的,周围有2或3个活细胞时可以活,对应上面的第(3)种情况
2、当细胞是死的,周围有3个活细胞时可以活,对应上面的第(2)种情况
所以每当满足以上两个条件的时候,如果是活细胞就记为3,死细胞就记为2。那么怎样计数呢?由于之前的状态在低位,所以只要每个状态&1就是本身的状态。
由于后来的状态在高位,那么最后的答案就是所有状态右移一位啦。
【代码】:
C++:
1 class Solution { 2 public: 3 int t[505][505]; 4 int dirx[8] = {0, 0, 1, 1, 1, -1, -1, -1}; 5 int diry[8] = {1, -1, 0, 1, -1, 0, 1, -1}; 6 void gameOfLife(vector<vector<int>>& board) { 7 int n = board.size(); 8 if (n == 0)return; 9 int m = board[0].size(); 10 for (int i = 0; i < n; i++) 11 { 12 for (int j = 0; j < m; j++) 13 { 14 int num1 = 0; 15 for(int ii = 0; ii < 8; ii++) 16 { 17 int x = i + dirx[ii]; 18 int y = j + diry[ii]; 19 if (x >= 0 && x < n && y >=0 && y < m && board[x][y]) 20 num1++; 21 } 22 if (board[i][j] == 0) 23 { 24 if(num1 == 3)t[i][j] = 1; 25 else t[i][j] = 0; 26 } 27 else 28 { 29 if(num1 == 2 || num1 == 3)t[i][j] = 1; 30 else t[i][j] = 0; 31 } 32 } 33 } 34 for (int i = 0; i < n; i++) 35 for (int j = 0; j < m; j++) 36 board[i][j] = t[i][j]; 37 } 38 };
Python3:
1 class Solution: 2 def __init__(self): 3 self.dire = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)] 4 def gameOfLife(self, board: List[List[int]]) -> None: 5 n = len(board) 6 if n == 0: return 7 m = len(board[0]) 8 for i in range(n): 9 for j in range(m): 10 num1 = 0 11 for d in self.dire: 12 x = i + d[0] 13 y = j + d[1] 14 if x >= 0 and x < n and y >= 0 and y < m: 15 num1 += board[x][y] & 1 16 if board[i][j] == 0 and num1 == 3: 17 board[i][j] = 2 18 elif board[i][j] == 1 and num1 in [2, 3]: 19 board[i][j] = 3 20 for i in range(n): 21 for j in range(m): 22 board[i][j] >>= 1 23
445. 两数相加 II(中等)
【分类】:栈、链表
【题解】:倒序首先就要想到栈啦,把两个链表的数据分别存入两个栈中,再依次取出相加即可,比忘了进位哦。
【代码】:
C++:
1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4 * int val; 5 * ListNode *next; 6 * ListNode(int x) : val(x), next(NULL) {} 7 * }; 8 */ 9 class Solution { 10 public: 11 ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { 12 stack<int> s1, s2; 13 while(l1 != NULL) 14 { 15 s1.push(l1->val); 16 l1 = l1->next; 17 } 18 while(l2 != NULL) 19 { 20 s2.push(l2->val); 21 l2 = l2->next; 22 } 23 int c = 0; 24 ListNode* ans = NULL; 25 while(!s1.empty() || !s2.empty() || c != 0) 26 { 27 int t1 = s1.empty() ? 0: s1.top(); 28 int t2 = s2.empty() ? 0: s2.top(); 29 if(!s1.empty())s1.pop(); 30 if(!s2.empty())s2.pop(); 31 int t = t1 + t2 + c; 32 int now = t % 10; 33 c = t / 10; 34 ListNode* cur = new ListNode(); 35 cur->val = now; 36 cur->next = ans; 37 ans = cur; 38 } 39 return ans; 40 } 41 };
Python3:
1 # Definition for singly-linked list. 2 # class ListNode: 3 # def __init__(self, x): 4 # self.val = x 5 # self.next = None 6 7 class Solution: 8 def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: 9 s1 = [] 10 s2 = [] 11 while(l1): 12 s1.append(l1.val) 13 l1 = l1.next 14 while(l2): 15 s2.append(l2.val) 16 l2 = l2.next 17 c = 0 18 ans = None 19 while(s1 or s2 or c != 0): 20 t1 = 0 if not s1 else s1.pop() 21 t2 = 0 if not s2 else s2.pop() 22 t = t1 + t2 + c 23 now = t % 10 24 c = t // 10 25 cur = ListNode(now) 26 cur.next = ans 27 ans = cur 28 return ans