LeetCode 01-10题
正文
# 第一个 if target - num in hash_mapping.keys(): for i, num in enumerate(nums): # 第二个,排序 for i in range(len(nums)): nums[i] = [i, nums[i]] nums.sort(key=lambda num : num[1]) # 第三个 # 倘若 cur = ListNode(t % 10, None),他指向的是一个新的存储单元,原本标签数据并不会修改 # 非常的坑爹,这是灵活的使用头结点! cur.next = ListNode(t % 10, None) # 第四个 python Class 函数中 第一个参数 self 一定要记得写 # 第五个 info = [0 for i in range(N)] s = '@#' + '#'.join([ch for ch in s]) + '#$' info[i] = min(info[2 * id - i], mx - i) if mx > i else 1 # 第六个 res = [[] for i in range(numRows)] ret += ''.join(res[i]) res = [""] * numRows # 等价于 res = ["" for i in range(numRows)] ''.join(res) # 第七个 str_res = str(x)[::-1] if x >= 0 else '-' + str(x)[1:][::-1] # 使用了切片大法 str_x = str_x[::-1] str_x = ''.join(reversed(str_x)) print('0 011112'.lstrip(' 01')) # 可以将前面的 0 空格 1 全部去掉,并没有要求他们连着 if -2 ** 31 <= str_x <= 2 ** 31 - 1: return 1 # 第十个 # 使用 python 写Dp class Solution: def isMatch(self, s: str, p: str) -> bool: s, p = ' ' + s, ' ' + p n, m = len(s), len(p) f = [[False] * m for i in range(n)] f[0][0] = True for i in range(n): for j in range(1, m): if p[j] != '*': f[i][j] = i > 0 and f[i-1][j-1] and (s[i] == p[j] or p[j] == '.') else: f[i][j] = f[i][j-2] or i > 0 and f[i-1][j] and (s[i] == p[j-1] or p[j-1] == '.') return f[n-1][m-1]
string y = to_string(x); return y == string(y.rbegin(), y.rend()); vector<vector<bool> > f(n + 1, vector<bool>(m + 1));
0.找到的超级精简的代码
第一题
class Solution: def twoSum(self, nums: List[int], target: int) -> List[int]: """ :type nums: List[int] :type target: int :rtype: List[int] """ dic = {} for i, num in enumerate(nums): rest = target - num if rest in dic: return [i, dic[rest]] dic[num] = i 作者:为什么这么多题哭 链接:https://www.acwing.com/activity/content/code/content/333354/ 来源:AcWing 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
第二题
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: head = ListNode() cur = head t = 0 while l1 is not None or l2 is not None or t != 0: if l1 is not None: t += l1.val l1 = l1.next if l2 is not None: t += l2.val l2 = l2.next cur.next = ListNode(t % 10, None) cur = cur.next t = t // 10 return head.next
第三题
第三题找的代码比较多,也是各有特色
- 使用精简的 while 循环一个顶俩,使用 set 维护当前的子字符串
class Solution: def lengthOfLongestSubstring(self, s: str) -> int: myset = set() i, j, n = 0, 0, len(s) max_length = 0 while i < n: if s[i] not in myset: myset.add(s[i]) max_length = max(max_length, i - j + 1) i += 1 else: myset.remove(s[j]) j += 1 return max_length
- 使用了字典来记录当前重复字符的位置
class Solution: def lengthOfLongestSubstring(self, s: str) -> int: max_ch_pos = {} i, j, n = 0, 0, len(s) max_length = 0 while i < n: if s[i] not in max_ch_pos: # max ch pos 记录的是当前 char 对应的 position max_ch_pos[s[i]] = i max_length = max(max_length, i - j + 1) i += 1 else: j = max(max_ch_pos[s[i]] + 1, j) max_ch_pos[s[i]] = i max_length = max(max_length, i - j + 1) i += 1 return max_length
1. Two Sum
题目链接
本题大致有三个思路,
第一个是直接暴力,使用指针遍历列表,做法,
第二种是只用 Hash表,python库函数做法,
第三种是双指针做法,
下面为三种方法的代码:
- 暴力求解办法
class Solution: def twoSum(self, nums: List[int], target: int) -> List[int]: for i in range(0, len(nums)): for j in range(i + 1, len(nums)): if nums[i] + nums[j] == target: return [i, j]; return [-1, -1];
- 使用字典 hash
倘若是 C++ 使用 map 或者是 unordered_map
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int, int> heap; int r; for (int i = 0; i < nums.size(); i ++ ) { r = target - nums[i]; if (heap.count(r)) { return {i, heap[r]}; } else { heap[nums[i]] = i; } } return {}; // 这个是为了防止语法报错 } };
首先字典预先存储 values -> indices 的映射,然后我们对每一个数字 num,查找 target - nums 是否在字典中存在,以及是不是他自己
不过,因为涉及到可能存在多个 value,这里存在bug,所以说我直接是 一个 value 对应一个 indices 列表
class Solution: def twoSum(self, nums: List[int], target: int) -> List[int]: hash_mapping = {} # 进行 hash 字典,他是一个 int -> list[int] 的映射 for i in range(0, len(nums)): if nums[i] in hash_mapping.keys(): hash_mapping[nums[i]].append(i) else: hash_mapping[nums[i]] = [i] for i in range(len(nums)): num = nums[i] if target - num in hash_mapping.keys(): cur_list = hash_mapping[target - num] flag = False for indice in cur_list: if indice != i: return [i, indice]
但是仔细想来,没必要使用列表,因为题目保证了唯一解,倘若有多个数字相同,而且他还与答案相关,情况一,为他是答案的一个数,另一个数和他不同,那么 list 为 int->int 的映射没有问题。 情况二,答案的两个数字都是她,那也不怕也能得到正确结果
class Solution: def twoSum(self, nums: List[int], target: int) -> List[int]: heap = {} for i in range(len(nums)): if target - nums[i] in heap.keys(): return [i, heap[target-nums[i]]] else: heap[nums[i]] = i return []
- 双指针算法
算法竞赛中采用的做法,因为要保留原地址的indice ,所以说list需要扩展一下在进行排序。
那么排序之后是如何做的呢?
使用i, j 指针分别指向排序后的数组a, 然后比较 a[i].val + a[j].val 与 target 的大小,如果 a[i].val + a[j].val > target,那么我们应该 j -- ,保证运算后的 a[i].val + a[j].val 变小,已达到向 target 贴近的目的,否则 i ++, 使得a[i].val + a[j].val变大。
至于为什么可以知道最终的唯一解呢?
对于此时的 a[i].val + a[j].val < target, 说明 i 对于所有的 j 都无法组成 target,因为此时保证有解的最大的a[j].val都小于 target,同理 > target 也是一样的道理。
class Solution: def twoSum(self, nums: list, target: int) -> list[int]: # 首先,我们需要对 nums 扩展数组进行排序 for i in range(len(nums)): nums[i] = [i, nums[i]] nums.sort(key=lambda num: num[1]) # 按照第二关键字进行排序 i, j = 0, len(nums) - 1 while i < j: if nums[i][1] + nums[j][1] == target: return [nums[i][0], nums[j][0]] elif nums[i][1] + nums[j][1] > target: j -= 1 else: i += 1 return []
Add Two Number
如果大伙之前接触过大整数相加的话,这就是一个链表的模拟办法,不过是和C/C++不同,C/C++的参数传递很是方便,引用、值传递、指针;使用 python 的时候,就会有一些注意事项
正常按位相加,进一处理就可以了
这里我先写一个 C++代码找找感觉:注意使用一个头结点,使得我们不需要处理空节点等等特殊的情况,非常的方便。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { // 首先我们定义一个虚拟头结点,直接帮助我们处理了为空,等等特别难搞的问题 ListNode *head = new ListNode(); ListNode *cur = head; int t = 0; while (l1 || l2 || t) { if (l1) t += l1->val, l1 = l1->next; if (l2) t += l2->val, l2 = l2->next; cur->next = new ListNode(t % 10, nullptr); cur = cur->next; t /= 10; } return head->next; } };
Python的代码:
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: head = ListNode() cur = head t = 0 while l1 is not None or l2 is not None or t != 0: if l1 is not None: t += l1.val l1 = l1.next if l2 is not None: t += l2.val l2 = l2.next cur.next = ListNode(t % 10, None) cur = cur.next t = t // 10 return head.next
3. Longest Substring Without Repeating Characters
本题就是一个双指针的题目,然后加上一个字典存储每个字符出现的次数
不过从本质上来说,这个题目的解题思路是,首先将这个 个字符串进行了分类,分为了 个类别,主要是以 0,1,.. n 为结尾的类别。
然后发现这 n 个类别之间在不重复字符上进行递进的关系
C++代码
class Solution { public: int lengthOfLongestSubstring(string s) { unordered_map<char, int> heap; int j = 0; int res = 0; for (int i = 0; i < s.size(); i ++ ) { heap[s[i]] ++; while (heap[s[i]] > 1) { heap[s[j]] --; j ++; } res = max(res, i - j + 1); } return res; } };
Python 代码
class Solution: def lengthOfLongestSubstring(self, s: str) -> int: dic = {} j, res = 0, 0 for i in range(len(s)): if s[i] in dic: dic[s[i]] += 1 else: dic[s[i]] = 1 while dic[s[i]] > 1: dic[s[j]] -= 1 j += 1 res = max(res, i - j + 1) return res
4. Median of Two Sorted Arrays
暴力解法
倘若是使用暴力的方法来写,就是
class Solution: def findMedianSortedArrays(self, nums1: list, nums2: list) -> float: m, n = len(nums1), len(nums2) if (m + n) % 2 == 0: # find two number ret = self.getKey(nums1, nums2, (m + n) // 2 - 1, True) # 1, 1, --> 0, 1 else: # find one number ret = self.getKey(nums1, nums2, (m + n) // 2, False) # 1, 0, --> 0 return ret def getKey(self, nums1: list, nums2: list, k: int, flag: bool): i, j = 0, 0 drop_num = -1; for tmp in range(0, k + 1): if i >= len(nums1): drop_num = nums2[j] j += 1 elif j >= len(nums2): drop_num = nums1[i] i += 1 else: if nums1[i] <= nums2[j]: drop_num = nums1[i] i += 1 else: drop_num = nums2[j] j += 1 if not flag: return drop_num else: if i == len(nums1): drop_num += nums2[j] elif j == len(nums2): drop_num += nums1[i] else: drop_num += min(nums1[i], nums2[j]) return drop_num / 2 if __name__ == "__main__": solution = Solution() nums1 = [1, 3] nums2 = [2] print(solution.findMedianSortedArrays(nums1, nums2)) nums1 = [1, 2] nums2 = [3, 4] print(solution.findMedianSortedArrays(nums1, nums2)) nums1 = [0, 0] nums2 = [0, 0] print(solution.findMedianSortedArrays(nums1, nums2)) nums1 = [] nums2 = [1] print(solution.findMedianSortedArrays(nums1, nums2)) nums1 = [2] nums2 = [] print(solution.findMedianSortedArrays(nums1, nums2))
那么如何达到他所规定的 呢?
本题难度较大,我就多说几句:
倘若是想要达到他的复杂度,最好想的办法就是使用 递归二分处理,思路如下:
c++代码
对应的 C++ 代码如下所示:
class Solution { public: double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int n = nums1.size(), m = nums2.size(), t = n + m; int x = t / 2; if (t % 2 == 0) { // even 2 * x --> (x, x + 1) // printf("even\n"); return (find(nums1, 0, nums2, 0, x) + find(nums1, 0, nums2, 0, x + 1)) / 2.0; } else { // odd, 2 * x + 1 --> x // printf("odd\n"); return find(nums1, 0, nums2, 0, x + 1); } } void Show(vector<int> &v) { for (int i = 0; i < v.size(); i ++ ) { printf("%d ", v[i]); } cout << endl; } // 在有序数组 nums1[s1:] 和 nums2[s2:] 有序数组中查找第 k 大的数字 double find(vector<int> &nums1, int s1, vector<int> &nums2, int s2, int k) { // printf("nums1:%d, nums2:%d, k:%d\n", s1, s2, k); // Show(nums1); // Show(nums2); // 为了方便,我们这里假设的是 nums1 进行计算的长度小于 nums2 进行计算的长度 if (nums1.size() - s1 > nums2.size() - s2) { return find(nums2, s2, nums1, s1, k); } // 倘若 nums1 已经被用光了 if (nums1.size() == s1) { return nums2[s2 + k - 1]; } // 倘若只要选择一个 if (k == 1) { return min(nums1[s1], nums2[s2]); } int si = min(s1 + k / 2 - 1, (int)nums1.size() - 1); int sj = (k - k / 2) + s2 - 1; sj = k + s1 + s2 - 2 - si; if (nums1[si] == nums2[sj]) { return nums1[si]; } else if (nums1[si] < nums2[sj]) { return find(nums1, si + 1, nums2, s2, k - (si + 1 - s1)); } else { return find(nums1, s1, nums2, sj + 1, k - (sj + 1 - s2)); } } };
Python 代码
思路和 C++一样,不过是这个 self. 写的真的烦
class Solution: def find(self, nums1: list, s1: int, nums2: list, s2: int, k: int): if len(nums1) - s1 > len(nums2) - s2: return self.find(nums2, s2, nums1, s1, k) if len(nums1) == s1: return nums2[s2 + k - 1] if k == 1: return min(nums1[s1], nums2[s2]) si = min(len(nums1) - 1, s1 + k // 2 - 1) sj = k + s1 + s2 - 2 - si if nums1[si] == nums2[sj]: return nums1[si] elif nums1[si] < nums2[sj]: return self.find(nums1, si + 1, nums2, s2, k - (si + 1 - s1)) else: return self.find(nums1, s1, nums2, sj + 1, k - (sj + 1 - s2)) def findMedianSortedArrays(self, nums1: list, nums2: list) -> float: n, m = len(nums1), len(nums2) t = n + m x = t // 2 if t % 2 == 0: # even return (self.find(nums1, 0, nums2, 0, x) + self.find(nums1, 0, nums2, 0, x + 1)) / 2 else: return self.find(nums1, 0, nums2, 0, x + 1)
5. 最长回文子串
本题主要考虑三种做法,第一种是暴力写法,第二种是字符串Hash + 二分查找,第三种是马拉车算法,下面我就这三种写法一一给出代码和思路:
暴力解法
暴力做法的思路就是我们枚举回文的中心点,然后不断的向外扩散,不断枚举,查看以某字符为中心点的最大回文半径。该问题具体书写代码时,需要分别计算回文串的长度奇偶的问题。
c++
class Solution { public: string str; string longestPalindrome(string s) { str = s; return get_answer_violence(); } string get_answer_violence() { // odd if (str.size() == 0) { return ""; } string ret_str = ""; int ret = 0, tmp_ret = 1; for (int i = 0; i < str.size(); i ++ ) { tmp_ret = 1; for (int j = 1; true; j ++ ) { if (i - j >= 0 && i + j < str.size() && str[i - j] == str[i + j]) { tmp_ret += 2; } else { break; } } if (tmp_ret > ret) { ret = tmp_ret; ret_str = str.substr(i - tmp_ret / 2, tmp_ret); } } // even for (int i = 0; i < str.size() - 1; i ++ ) { tmp_ret = 0; for (int j = 1; true; j ++ ) { if (i - j + 1 >= 0 && i + j < str.size() && str[i - j + 1] == str[i + j]) { tmp_ret += 2; } else { break; } } if (tmp_ret > ret) { ret = tmp_ret; ret_str = str.substr(i - tmp_ret / 2 + 1, tmp_ret); } } return ret_str; } };
然而,看看大佬写的 c++ 代码,我有些弱爆了。。。
class Solution { public: string longestPalindrome(string s) { string ret = ""; for (int i = 0; i < s.size(); i ++ ) { int l = i - 1, r = i + 1; while (l >= 0 && r < s.size() && s[l] == s[r]) { l --, r ++; } if (r - l - 1 > ret.size()) { //(r - 1) - (l = 1) + 1 ret = s.substr(l + 1, r - l - 1); } l = i, r = i + 1; while (l >= 0 && r < s.size() && s[l] == s[r]) { l --, r ++; } if (r - l - 1 > ret.size()) { //(r - 1) - (l = 1) + 1 ret = s.substr(l + 1, r - l - 1); } } return ret; } };
对应的 Python
代码
class Solution: def longestPalindrome(self, s: str) -> str: n = len(s) max_len = 1 if n == 0: return "" real_left, real_right = 0, 0 for i in range(n): # odd l, r = i - 1, i + 1 while l >= 0 and r < n and s[l] == s[r]: l -= 1 r += 1 if r - l - 1 > real_right - real_left + 1: real_left, real_right = l + 1, r - 1 l, r = i, i + 1 while l >= 0 and r < n and s[l] == s[r]: l -= 1 r += 1 if r - l - 1 > real_right - real_left + 1: real_left, real_right = l + 1, r - 1 return s[real_left:real_right + 1]
Hash 字符串 + 二分
暴力做法的思路就是我们枚举回文的中心点,然后不断的向外扩散,不断枚举,查看以某字符为中心点的最大回文半径。分析暴力所存在的问题,不难发现,他枚举寻找最大回文半径这个地方过于耗时。每次寻找 ** 最大,我们都应该想想是否可以使用二分呢?比较字符串的相等,当然是没有办法使用二分的;但是我们将字符串进行 Hash 之后就可以了!
所以说 字符串 Hash + 二分的做法,其实是对暴力算法的改进!
同时,为了避免像是暴力做法中的就讨论,我们这里对字符串插入了 特殊字符'#' (只需要不在原字符串中出现即可)。
typedef unsigned long long ULL; const int N = 2010, BASE = 259; ULL hl[N], hr[N], p[N]; char str[N]; int n; class Solution { public: ULL get_left(int i, int j) { return hl[j] - hl[i - 1] * p[j - i + 1]; } ULL get_right(int i, int j) { return hr[i] - hr[j + 1] * p[j - i + 1]; } string longestPalindrome(string s) { // 处理字符串 n = s.size(); s = ' ' + s; for (int i = n * 2; i > 0; i -= 2) { str[i] = s[i / 2]; str[i - 1] = '#'; } n = n * 2 + 1; str[n] = '#'; str[n + 1] = '\0'; // 字符串 Hash p[0] = 1, hl[0] = 0, hr[n + 1] = 0; for (int i = 1, j = n; i <= n; i ++, j -- ) { p[i] = p[i - 1] * BASE; hl[i] = hl[i - 1] * BASE + str[i]; hr[j] = hr[j + 1] * BASE + str[j]; } // 二分查找回文半径 int l, r, mid; int real_left = 0, real_right = 0; int cur_len = 0; for (int i = 1; i <= n; i ++ ) { l = 0, r = min(i - 1, n - i); while (l < r) { mid = l + r + 1 >> 1; if (get_left(i - mid, i) == get_right(i, i + mid)) { l = mid; } else { r = mid - 1; } } if (cur_len < l) { cur_len = l; real_left = i - l; real_right = i + l; } } string ret = ""; for (int i = real_left; i <= real_right; i ++ ) { if (str[i] != '#') { ret = ret + str[i]; } } return ret; } };
对应的 Python
代码
马拉车算法
不会 Manacher的可以去百度,Bilibili上也有很多的讲解视频。
首先,我想先给出一个平常的Manacher算法
#include <bits/stdc++.h> using namespace std; const int N = 2000010; int p[N]; char s[N], str[N]; int len1, len2; void Init() { len1 = strlen(s); str[0] = '@'; str[1] = '#'; for (int i = 0; i < len1; i ++ ) { str[i * 2 + 2] = s[i]; str[i * 2 + 3] = '#'; } len2 = len1 * 2 + 1; str[len2 + 1] = '$'; // 因为我们并未对他的边界进行特判,所以说这里的东西,纯纯就是哨兵 } void Manacher() { // id 指的是中心点,mx指的是中心点尚未到达的点 int id = 0, mx = 0; for (int i = 1; i <= len2; i ++ ) { if (mx > i) p[i] = min(p[2 * id - i], mx - i); else p[i] = 1; while (str[i + p[i]] == str[i - p[i]]) { p[i] ++; } if (i + p[i] > mx) { mx = i + p[i]; id = i; } } } int main() { int cur_cnt = 0; while (scanf("%s", s), strcmp(s, "END")) { Init(); Manacher(); int ans = 0; for (int i = 1; i <= len2; i ++ ) { ans = max(p[i] - 1, ans); } printf("Case %d: %d\n", ++ cur_cnt, ans); } return 0; }
将该算法应用到我们的题目上(是说话,马拉车算法挺好写的):
const int N = 2010; char str[N]; int len1, len2; int p[N]; class Solution { public: string longestPalindrome(string s) { // initial len1 = s.size(); str[0] = '@'; str[1] = '#'; for (int i = 0; i < len1; i ++ ) { str[i * 2 + 2] = s[i]; str[i * 2 + 3] = '#'; } len2 = len1 * 2 + 1; str[len2 + 1] = '$'; // @ 和 $ 这两个符号就是起到了收尾烧饼的作用,因为我们并不会判断马拉车过程中是否会越界 // Manacher int mx = 0, id = 0; int ans = 0; for (int i = 1; i <= len2; i ++ ) { if (i < mx) p[i] = min(p[2 * id - i], mx - i); else p[i] = 1; while (str[i + p[i]] == str[i - p[i]]) { // 需要哨兵看管 p[i] ++; } if (mx < i + p[i]) { mx = i + p[i]; id = i; } if (p[i] - 1 > ans) { ans = p[i] - 1; } } cout << ans << endl; for (int i = 1; i <= len2; i ++ ) { if (p[i] - 1 == ans) { string ret = ""; for (int j = i - p[i] + 1; j <= i + p[i] - 1; j ++ ) { if (str[j] != '#') { ret += str[j]; } } return ret; } } return ""; } };
找的大佬的 python
Manacher
算法,并按照自己的习惯进行了注释和修改
N = 2000010 info = [0 for i in range(N)] # 就是我们的回文半径 P s = input() cur_cnt = 1 while s != 'END': # 下一步是初始化,对源字符串进行处理,抛去奇偶性 s = '@#' + '#'.join([s[i] for i in range(len(s))]) + '#$' # 进行 Manacher 算法 id, mx = 0, 0 ans = 0 # print(s) for i in range(1, len(s) - 1): # 下面这个 if else 的使用很有意思,因为我很少这样用。。。 info[i] = min(info[2 * id - i], mx - i) if mx > i else 1 while s[i + info[i]] == s[i - info[i]]: info[i] += 1 if mx < i + info[i]: mx = i + info[i] id = i ans = max(ans, info[i] - 1) print('Case ' + str(cur_cnt) + ': ' + str(ans)) cur_cnt += 1 s = input()
对应的 Python
代码
N = 2010 info = [0 for i in range(N)] class Solution: def longestPalindrome(self, s: str) -> str: # initial the string s = '@#' + '#'.join([ch for ch in s]) + '#$' # Manacher mx, id = 0, 0 max_left, max_right = 0, 0 for i in range(1, len(s) - 1): info[i] = min(info[id * 2 - i], mx - i) if mx > i else 1 while s[i + info[i]] == s[i - info[i]]: info[i] += 1 if i + info[i] > mx: mx = i + info[i] id = i if max_right - max_left < 2 * info[i] - 1: max_left, max_right = i - info[i] + 1, i + info[i] - 1 return s[max_left + 1:max_right:2]
6. ZigZag Conversion
使用指针指向当前的层数
就是假如说 numRows = 5, 当前层数应该是 1 2 3 4 5 4 3 2 1 2 3 4 5 4 3 2 1,不断这样指向当前的层数,存入到我们的 string 字符串中即可
对应的 C++ 代码
class Solution { public: string convert(string s, int numRows) { if (numRows == 1) { return s; } vector<string> vs(numRows + 1); int cur_ptr = 1; bool down = true; for (int i = 0; i < s.size(); i ++ ) { vs[cur_ptr] += s[i]; if (down) { if (cur_ptr != numRows) cur_ptr += 1; else cur_ptr -= 1, down = false; } else { if (cur_ptr != 1) cur_ptr -= 1; else cur_ptr += 1, down = true; } } string ret = ""; for (int i = 1; i < vs.size(); i ++ ) { ret += vs[i]; } return ret; } };
对应的 Python 代码
class Solution: def convert(self, s: str, numRows: int) -> str: if numRows == 1: return s cur_level, down = 1, True str_list = ["" for i in range(numRows + 1)] for ch in s: str_list[cur_level] += ch if down: if cur_level == numRows: cur_level -= 1 down = False else: cur_level += 1 else: if cur_level == 1: cur_level += 1 down = True else: cur_level -= 1 ret = "" for i in range(1, numRows + 1): ret += str_list[i] return ret
风格不同的python代码
首先是,一个思路和我一模一样的代码,但是精简程度,把我看哭了
class Solution: def convert(self, s: str, numRows: int) -> str: # 两种不需要处理的特判 if numRows == 1 or len(s) <= numRows: return s res = [""] * numRows # 等价于 res = ["" for i in range(numRows)] cur_row, step = 0, 1 for ch in s: res[cur_row] += ch if cur_row == 0: step = 1 elif cur_row == numRows - 1: step = -1 cur_row += step return "".join(res)
这里重网上找了一个差不多思路,但是代码风格有些不同的python代码,主要是用了
res = [[] for i in range(numRows)]
ret += ''.join(res[i])
我觉着比较有趣
class Solution: def convert(self, s: str, numRows: int) -> str: # 两种不需要处理的特判 if numRows == 1 or len(s) <= numRows: return s # 比较有趣的生成数组的方法 res = [[] for i in range(numRows)] # res 是一个列表的列表,用来记录每一行的字符串 cur_idx, n = 0, len(s) while cur_idx < n: for i in range(0, numRows): if cur_idx < n: res[i].append(s[cur_idx]) cur_idx += 1 else: break for i in range(numRows - 2, 0, -1): if cur_idx < n: res[i].append(s[cur_idx]) cur_idx += 1 else: break ret = "" for i in range(len(res)): ret += ''.join(res[i]) return ret
7. Reverse Integer
使用 long long 进行模拟
c++ 代码
typedef long long LL; class Solution { public: int reverse(LL x) { bool is_positive = true; if (x >= 0) { is_positive = true; } else { is_positive = false; x = -x; } LL down_x = -(1LL << 31), up_x = (1LL << 31) - 1; cout << up_x << endl << down_x << endl; LL ret = 0LL; while (x) { ret = ret * 10 + x % 10; x /= 10; } if (is_positive == false) { ret = -ret; } if (ret <= up_x && ret >= down_x) { return ret; } else { return 0; } } };
python 代码可以直接使用有趣的字符串翻转
class Solution: def reverse(self, x: int) -> int: y = abs(x) str_x = str(y) # 字符串翻转的方法 # print(''.join(reversed(str_x))) str_x = str_x[::-1] str_x.lstrip('0') if x < 0: str_x = '-' + str_x str_x = int(str_x) # print(str_x) if -2 ** 31 <= str_x <= 2 ** 31 - 1: # 注意这个表达式,看起来很是舒服 return str_x else: return 0
更为精简一些
主要是使用了切片
class Solution: def reverse(self, x: int) -> int: str_res = str(x)[::-1] if x >= 0 else '-' + str(x)[1:][::-1] res = int(str_res) if -2 ** 31 <= res <= 2 ** 31 - 1: return res else: return 0
8. String to Integer (atoi)
C++暴力模拟
比较坑的是,需要去除首部 0
typedef long long LL; class Solution { public: int myAtoi(string s) { // 首先去除行前的空格 int st = 0; while (s[st] == ' ') st ++; // 然后查看 +-号 bool is_positive = true; if (s[st] == '+') { is_positive = true; st += 1; } else if (s[st] == '-') { is_positive = false; st += 1; } else { is_positive = true; } // 这里需要去除几个零。。。。。绝绝子 while (s[st] == '0') st ++; // 查看小数的部分 int ed = st; while (ed < s.size() && s[ed] >= '0' && s[ed] <= '9') ed ++; // 特判是否超出范围 LL upper_boundary = (1LL << 31) - 1, lower_boundary = -(1LL << 31); if (ed - st >= 11) { if (is_positive) { return upper_boundary; } else { return lower_boundary; } } // 进行数字转换 LL num = 0; for (int i = st; i < ed; i ++ ) { num = num * 10 + s[i] - '0'; } if (is_positive == false) { num = -num; } // 返回结果 if (num >= upper_boundary) { return upper_boundary; } else if (num <= lower_boundary) { return lower_boundary; } else { return num; } } };
Python使用自身特性
lstrip
int 强制类型转化 str
不过这些特判比较麻烦,全是 '+'或者'-',这是空字符串,或者是全是字母
class Solution: def myAtoi(self, s: str) -> int: s = s.lstrip(' ') if s == '': return 0 st, ed = 0, 0 if s[0] == '+' or s[0] == '-': ed = 1 # 这个 ed = 1,保证了 + - 号不被判断,但是又被 st 包含其中,可以被转换 while ed < len(s) and '0' <= s[ed] <= '9': ed += 1 s = s[st:ed] x = int(s) if s != '' and s != '+' and s != '-' else 0 if x > 2 ** 31 - 1: return 2 **31 - 1 elif x < -2 ** 31: return -2 ** 31 else: return x
9. Palindrome Number
使用数字
c++
代码
typedef long long LL; class Solution { public: bool isPalindrome(int x) { // 特判负数 if (x < 0) { return false; } // 颠倒过来的数字 LL y = 0, z = x; while (z) { y = y * 10 + z % 10; z /= 10; } // 判断是否相等 return x == y; } };
python
代码:
class Solution: def isPalindrome(self, x: int) -> bool: if x < 0: return False y, z = 0, x while z != 0: y = y * 10 + z % 10 z //= 10 return x == y
使用字符串
c++
代码
typedef long long LL; class Solution { public: bool isPalindrome(int x) { // 特判负数 if (x < 0) { return false; } // 颠倒过来的数字 string s = ""; while (x) { s += '0' + x %10; x /= 10; } // 判断是否相等 for (int i = 0; i < s.size() / 2; i ++ ) { if (s[i] != s[s.size() - i - 1]) { return false; } } return true; } };
甚至还可以:
class Solution { public: bool isPalindrome(int x) { string y = to_string(x); return y == string(y.rbegin(), y.rend()); } };
python
代码:
class Solution: def isPalindrome(self, x: int) -> bool: x = str(x) return x == x[::-1]
10. Regular Expression Matching
进行暴力DFS
c++
代码
class Solution { public: string s, p; int n, m; bool isMatch(string s1, string p1) { s = s1, p = p1; n = s.size(), m = p.size(); return dfs(0, 0); } bool dfs(int i, int j) { if (i == n && j == m) { // match return true; } else if (j == m) { // && i != n return false; } // 判断 * 的问题 int cur_ed = -1; if (j + 1 < m && p[j + 1] == '*') { cur_ed = j + 2; while (cur_ed < m && p[cur_ed] == '*') cur_ed ++; } if (cur_ed == -1) { // 没有 * if (p[j] == '.') { return dfs(i + 1, j + 1); } else { return s[i] == p[j] && dfs(i + 1, j + 1); } } else { // 至少后面存在一个 * if (p[j] == '.') { for (int k = i; k <= n; k ++ ) { // 一个不匹配到全部匹配 if (dfs(k, cur_ed)) { return true; } } return false; } else { if (dfs(i, cur_ed)) { // 一个都不匹配 return true; } for (int k = i; k < n; k ++ ) { // 判断是否可以字母对应上 if (s[k] == p[j]) { if (dfs(k + 1, cur_ed)) { return true; } } else { return false; // 中间存在不匹配的现象了 } } return false; } } } };
使用 动态规划 DP
c++
代码
class Solution { public: bool isMatch(string s, string p) { int n = s.size(), m = p.size(); s = ' ' + s; p = ' ' + p; vector<vector<bool> > f(n + 1, vector<bool>(m + 1)); // memset(f, false, sizeof f); f[0][0] = true; for (int i = 0; i <= n; i ++ ) { for (int j = 1; j <= m; j ++ ) { if (p[j] != '*') { if (i == 0) { continue; } else { f[i][j] = f[i - 1][j - 1] && (s[i] == p[j] || p[j] == '.'); } } else { f[i][j] = f[i][j - 2]; if (i > 0 && (s[i] == p[j-1] || p[j-1] == '.')) { f[i][j] = f[i][j] || f[i-1][j]; } } } } return f[n][m]; } };
python
代码
class Solution: def isMatch(self, s: str, p: str) -> bool: s, p = ' ' + s, ' ' + p n, m = len(s), len(p) f = [[False] * m for i in range(n)] f[0][0] = True for i in range(n): for j in range(1, m): if p[j] != '*': f[i][j] = i > 0 and f[i-1][j-1] and (s[i] == p[j] or p[j] == '.') else: f[i][j] = f[i][j-2] or i > 0 and f[i-1][j] and (s[i] == p[j-1] or p[j-1] == '.') return f[n-1][m-1]
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)