正文
本博客记录的是 LeetCode 21 到 30 题的题解
之前很少使用的语法
| |
| |
| |
| |
| |
| |
| from heapq import * |
| class Solution: |
| def mergeKLists(self, lists: List[ListNode]) -> ListNode: |
| |
| heap = [] |
| for i, l in enumerate(lists): |
| if l: |
| heappush(heap, (l.val, i)) |
| |
| |
| dummy = cur = ListNode() |
| while (heap): |
| val, i = heappop(heap) |
| cur.next = lists[i] |
| lists[i] = lists[i].next |
| cur = cur.next |
| if lists[i]: |
| heappush(heap, (lists[i].val, i)) |
| |
| return dummy.next |
| |
| |
| h[i] = (h[i - 1] * BASE + ord(s[i])) % MOD |
| |
| |
| # 30 非常容易出Bug的地方,因为ps.size()会变化 |
| for (int i = j; i < ps.size(); i ++ ) { |
| ps.pop_back(); |
| } |
21. Merge Two Sorted Lists
直接就是使用 头结点 dummy
,然后进行指针移动即可。
c++代码
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| class Solution { |
| public: |
| ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) { |
| ListNode *dummy = new ListNode(), *cur = dummy; |
| |
| while (list1 || list2) { |
| if (list1 == nullptr) { |
| cur->next = list2; |
| list2 = nullptr; |
| } else if (list2 == nullptr) { |
| cur->next = list1; |
| list1 = nullptr; |
| } else { |
| if (list1->val <= list2->val) { |
| cur->next = list1; |
| list1 = list1->next; |
| cur = cur->next; |
| } else { |
| cur->next = list2; |
| list2 = list2->next; |
| cur = cur->next; |
| } |
| } |
| } |
| return dummy->next; |
| } |
| }; |
python 代码
| |
| |
| |
| |
| |
| class Solution: |
| def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: |
| dummy = ListNode() |
| cur = dummy |
| while list1 or list2: |
| if not list1: |
| cur.next = list2 |
| list2 = None |
| elif not list2: |
| cur.next = list1 |
| list1 = None |
| else: |
| if list1.val <= list2.val: |
| cur.next = list1 |
| list1 = list1.next |
| cur = cur.next |
| else: |
| cur.next = list2 |
| list2 = list2.next |
| cur = cur.next |
| return dummy.next |
22. Generate Parentheses
一个挺简单的 DFS
C++ 代码
| class Solution { |
| public: |
| vector<string> res; |
| int n; |
| char s[110]; |
| vector<string> generateParenthesis(int x) { |
| n = x; |
| dfs(0, 0, 0); |
| return res; |
| } |
| |
| void dfs(int ptr, int cnt1, int cnt2) { |
| if (ptr == 2 * n) { |
| s[ptr] = '\0'; |
| res.push_back(string("") + s); |
| return; |
| } |
| if (cnt2 > cnt1) return; |
| if (cnt1 < n) { |
| s[ptr] = '('; |
| dfs(ptr + 1, cnt1 + 1, cnt2); |
| } |
| if (cnt2 < n) { |
| s[ptr] = ')'; |
| dfs(ptr + 1, cnt1, cnt2 + 1); |
| } |
| } |
| }; |
python 代码
| class Solution: |
| n = 0 |
| res = [] |
| s = [] |
| |
| def generateParenthesis(self, k: int) -> List[str]: |
| self.s = ['' for i in range(k * 2)] |
| self.n = k |
| self.res.clear() |
| self.dfs(0, 0, 0) |
| return self.res |
| |
| def dfs(self, ptr, cnt1, cnt2): |
| if ptr == self.n * 2: |
| self.res.append(''.join(self.s)) |
| return |
| if cnt1 < cnt2: |
| return |
| if cnt1 < self.n: |
| self.s[ptr] = '(' |
| self.dfs(ptr + 1, cnt1 + 1, cnt2) |
| if cnt2 < self.n: |
| self.s[ptr] = ')' |
| self.dfs(ptr + 1, cnt1, cnt2 + 1) |
23. Merge k Sorted Lists
纯暴力做法
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| class Solution { |
| public: |
| ListNode* mergeKLists(vector<ListNode*>& lists) { |
| ListNode *dummy = new ListNode(), *cur = dummy; |
| int cur_val = -1, cur_idx = -1; |
| int n = lists.size(); |
| while (true) { |
| cur_idx = cur_val = -1; |
| for (int i = 0; i < n; i ++ ) { |
| if (lists[i] == nullptr) continue; |
| else if (cur_idx == -1 || lists[i]->val < cur_val) { |
| cur_idx = i, cur_val = lists[i]->val; |
| } |
| } |
| if (cur_idx == -1) { |
| break; |
| } else { |
| cur->next = lists[cur_idx]; |
| cur = cur->next; |
| lists[cur_idx] = lists[cur_idx]->next; |
| } |
| } |
| return dummy->next; |
| } |
| }; |
使用堆优化
暴力做法中,我们不断循环,从 N 个链表中找到数最小的那个链表,进行插入,但是想要找到数字最小的链表,是 O(N)的,也就是说,太慢了。
最小值的话,不难想到直接使用堆进行维护!
c++ 代码
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| typedef pair<int, int> PII; |
| class Solution { |
| public: |
| ListNode* mergeKLists(vector<ListNode*>& lists) { |
| |
| priority_queue<PII, vector<PII>, greater<PII> > que; |
| int n = lists.size(); |
| for (int i = 0; i < n; i ++ ) { |
| if (lists[i] != nullptr) { |
| que.push(PII(lists[i]->val, i)); |
| } |
| } |
| |
| |
| ListNode *dummy = new ListNode(), *cur = dummy; |
| PII tmp; int idx; |
| while (que.empty() == false) { |
| idx = que.top().second; que.pop(); |
| cur->next = lists[idx]; |
| cur = cur->next; |
| lists[idx] = lists[idx]->next; |
| if (lists[idx] != nullptr) { |
| que.push(PII(lists[idx]->val, idx)); |
| } |
| } |
| |
| return dummy->next; |
| } |
| }; |
python 代码
| |
| |
| |
| |
| |
| from heapq import * |
| class Solution: |
| def mergeKLists(self, lists: List[ListNode]) -> ListNode: |
| |
| heap = [] |
| for i, l in enumerate(lists): |
| if l: |
| heappush(heap, (l.val, i)) |
| |
| |
| dummy = cur = ListNode() |
| while (heap): |
| val, i = heappop(heap) |
| cur.next = lists[i] |
| lists[i] = lists[i].next |
| cur = cur.next |
| if lists[i]: |
| heappush(heap, (lists[i].val, i)) |
| |
| return dummy.next |
| |
使用二分进行合并
倘若,我们假设有 k 个有序列表list1...listk,其中包含的元素个数分别是 n1..nk,而且n=n1+...+nk,
逐个进行两两合并的暴力做法的复杂度是:
n1∗(k−1)+n2∗(k−1)+n3∗(k−2)+n4∗(k−3)+...+nk−1∗2+nk
那么,我们现在使用二分合并的思想(有点像归并排序)进行求解
一定要记得归并的递归终点
len == 1
len == 0
| |
| |
| |
| |
| |
| class Solution: |
| lists = [] |
| def mergeKLists(self, mylists: List[ListNode]) -> ListNode: |
| |
| if not mylists: |
| return |
| self.lists = mylists |
| return self.myMergeKLists(0, len(self.lists) - 1) |
| |
| def myMergeKLists(self, l, r): |
| if l == r: |
| return self.lists[l] |
| elif l + 1 == r: |
| return self.mergeLists(self.lists[l], self.lists[r]) |
| else: |
| return self.mergeLists(self.myMergeKLists(l, (l + r) // 2), self.myMergeKLists((l + r) // 2 + 1, r)) |
| |
| def mergeLists(self, list1, list2): |
| dummy = ListNode() |
| cur = dummy |
| while list1 and list2: |
| if list1.val <= list2.val: |
| cur.next = list1 |
| cur = cur.next |
| list1 = list1.next |
| else: |
| cur.next = list2 |
| list2 = list2.next |
| cur = cur.next |
| if list1: |
| cur.next = list1 |
| elif list2: |
| cur.next = list2 |
| return dummy.next |
| |
| |
| |
| |
| |
| class Solution: |
| def mergeKLists(self, lists: List[ListNode]) -> ListNode: |
| |
| if not lists: |
| return |
| if len(lists) == 1: |
| return lists[0] |
| mid = len(lists) // 2 |
| return self.mergeLists(self.mergeKLists(lists[:mid]), self.mergeKLists(lists[mid:])) |
| |
| def mergeLists(self, list1, list2): |
| dummy = ListNode() |
| cur = dummy |
| while list1 and list2: |
| if list1.val <= list2.val: |
| cur.next = list1 |
| cur = cur.next |
| list1 = list1.next |
| else: |
| cur.next = list2 |
| list2 = list2.next |
| cur = cur.next |
| if list1: |
| cur.next = list1 |
| elif list2: |
| cur.next = list2 |
| return dummy.next |
24. Swap Nodes in Pairs
挺简单的一个指针交换
c++ 代码
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| class Solution { |
| public: |
| ListNode* swapPairs(ListNode* head) { |
| ListNode *dummy = new ListNode(), *cur = dummy, *cur1, *cur2; |
| dummy->next = head; |
| while (cur) { |
| if (cur->next == nullptr) { |
| break; |
| } |
| cur1 = cur->next; |
| if (cur1->next == nullptr) { |
| break; |
| } |
| cur2 = cur1->next; |
| cur->next = cur2; |
| cur1->next = cur2->next; |
| cur2->next = cur1; |
| cur = cur1; |
| } |
| return dummy->next; |
| } |
| }; |
python代码
| |
| |
| |
| |
| |
| class Solution: |
| def swapPairs(self, head: ListNode) -> ListNode: |
| cur = dummy = ListNode() |
| dummy.next = head |
| while cur: |
| cur1 = cur.next |
| if not cur1: |
| break |
| cur2 = cur1.next |
| if not cur2: |
| break |
| cur.next = cur2 |
| cur1.next = cur2.next |
| cur2.next = cur1 |
| cur = cur1 |
| return dummy.next |
25. Reverse Nodes in k-Group
使用数组交换指针
| |
| |
| |
| |
| |
| class Solution: |
| def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: |
| dummy = cur = ListNode() |
| dummy.next = head |
| tmp = [None for i in range(k)] |
| flag = True |
| while cur and cur.next and flag: |
| tmp[0] = cur.next |
| for i in range(1, k): |
| tmp[i] = tmp[i - 1].next |
| if tmp[i] is None: |
| flag = False |
| break |
| if flag == False: |
| break |
| cur.next = tmp[-1] |
| tmp[0].next = tmp[-1].next |
| for i in range(k - 1, 0, -1): |
| tmp[i].next = tmp[i - 1] |
| cur = tmp[0] |
| return dummy.next |
再来一种
| |
| class ListNode: |
| def __init__(self, val=0, next=None): |
| self.val = val |
| self.next = next |
| class Solution: |
| def reverseKGroup(self, head, k: int): |
| if k == 1: |
| return head |
| dummy = cur = ListNode() |
| dummy.next = head |
| length = 0 |
| while cur.next: |
| length += 1 |
| cur = cur.next |
| print(length) |
| cur = dummy |
| |
| for i in range(length // k): |
| first_node = cur.next |
| for j in range(k - 1): |
| if j == 0: |
| p, q = cur.next, cur.next.next |
| else: |
| p, q = q, tmp |
| tmp = q.next |
| q.next = p |
| cur.next = q |
| first_node.next = tmp |
| cur = first_node |
| |
| return dummy.next |
26. Remove Duplicates from Sorted Array
c++ coding
| class Solution { |
| public: |
| int removeDuplicates(vector<int>& nums) { |
| if (nums.size() == 0) { |
| return 0; |
| } |
| int j = 1, n = nums.size(); |
| for (int i = 1; i < n; i ++ ) { |
| if (nums[i] != nums[i - 1]) { |
| nums[j] = nums[i]; |
| j ++; |
| } |
| } |
| return j; |
| } |
| }; |
python coding
| class Solution: |
| def removeDuplicates(self, nums: List[int]) -> int: |
| j, n = 1, len(nums) |
| if n == 0: |
| return 0 |
| for i in range(1, n): |
| if nums[i] != nums[i - 1]: |
| nums[j] = nums[i] |
| j += 1 |
| return j |
27. Remove Element
c++ coding
| class Solution { |
| public: |
| int removeElement(vector<int>& nums, int val) { |
| int j = 0, n = nums.size(); |
| for (int i = 0; i < n; i ++ ) { |
| if (val != nums[i]) { |
| nums[j ++] = nums[i]; |
| } |
| } |
| return j; |
| } |
| }; |
python coding
| class Solution: |
| def removeElement(self, nums: List[int], val: int) -> int: |
| j, n = 0, len(nums) |
| for i in range(n): |
| if nums[i] != val: |
| nums[j] = nums[i] |
| j += 1 |
| return j |
28. Implement strStr()
字符串Hash
c++ 代码
| |
| |
| |
| typedef unsigned long long ULL; |
| const int N = 5 * 1e4 + 10, BASE = 31; |
| ULL a[N], p[N]; |
| class Solution { |
| public: |
| ULL get(int l, int r) { |
| return a[r] - a[l - 1] * p[r - l + 1]; |
| } |
| int strStr(string haystack, string needle) { |
| int m = haystack.size(), n = needle.size(); |
| |
| if (n == 0) return 0; |
| if (m < n) return -1; |
| |
| |
| ULL target = 0; |
| for (int i = 0; i < n; i ++ ) { |
| target = target * BASE + needle[i] - 'a'; |
| } |
| haystack = " " + haystack; |
| m += 1; |
| a[0] = 0; p[0] = 1; |
| for (int i = 1; i < m; i ++ ) { |
| a[i] = a[i - 1] * BASE + haystack[i] - 'a'; |
| p[i] = p[i - 1] * BASE; |
| } |
| |
| |
| for (int i = 1; i <= m - n; i ++ ) { |
| if (get(i, i + n - 1) == target) { |
| return i - 1; |
| } |
| } |
| return -1; |
| } |
| }; |
python 代码
| """ |
| Hash ord |
| """ |
| class Solution: |
| def modify(self, x, MOD): |
| x %= MOD |
| return x if x >= 0 else x + MOD |
| |
| def get(self, l, r, h, p, MOD): |
| return self.modify(h[r] - h[l - 1] * p[r - l + 1] % MOD, MOD) |
| |
| def strStr(self, s: str, s2: str) -> int: |
| N, BASE, MOD = 50010, 127, 1000000007 |
| |
| target = 0 |
| for ch in s2: |
| target = (target * BASE + ord(ch)) % MOD |
| |
| |
| s = " " + s |
| n = len(s) |
| h = [0] * (n + 10) |
| p = [0] * (n + 10) |
| h[0] = 0 |
| p[0] = 1 |
| for i in range(1, n): |
| h[i] = (h[i - 1] * BASE + ord(s[i])) % MOD |
| p[i] = p[i - 1] * BASE % MOD |
| |
| |
| m = len(s2) |
| for i in range(1, n - m + 1): |
| if self.get(i, i + m - 1, h, p, MOD) == target: |
| return i - 1 |
| return -1 |
KMP 解法
c++ 代码
| const int N = 5e4 + 10; |
| int ne[N]; |
| class Solution { |
| public: |
| int strStr(string haystack, string needle) { |
| if (needle == "") return 0; |
| if (needle.size() > haystack.size()) return -1; |
| |
| |
| int m = haystack.size(), n = needle.size(); |
| haystack = " " + haystack, needle = " " + needle; |
| |
| |
| ne[0] = ne[1] = 0; |
| int j = 0; |
| for (int i = 2; i <= n; i ++ ) { |
| while (j != 0 && needle[j + 1] != needle[i]) j = ne[j]; |
| if (needle[i] == needle[j + 1]) { |
| ne[i] = ++ j; |
| } else { |
| ne[i] = j; |
| } |
| } |
| |
| |
| j = 0; |
| for (int i = 1; i <= m; i ++ ) { |
| while (j != 0 && needle[j + 1] != haystack[i]) j = ne[j]; |
| if (haystack[i] == needle[j + 1]) { |
| j += 1; |
| if (j == n) { |
| return i - n; |
| } |
| } |
| } |
| return -1; |
| } |
| }; |
python 代码
| class Solution: |
| def strStr(self, s: str, p: str) -> int: |
| if p == '': |
| return 0 |
| elif len(s) < len(p): |
| return -1 |
| |
| |
| ne = [0] * 50010 |
| s, p = ' ' + s, ' ' + p |
| m, n = len(s), len(p) |
| j = 0 |
| for i in range(2, n): |
| while j != 0 and p[j + 1] != p[i]: |
| j = ne[j] |
| if p[j + 1] == p[i]: |
| j += 1 |
| ne[i] = j |
| |
| |
| j = 0 |
| for i in range(1, m): |
| while j != 0 and p[j + 1] != s[i]: |
| j = ne[j] |
| if p[j + 1] == s[i]: |
| j += 1 |
| if j == n - 1: |
| return i + 1 - n |
| return -1 |
29. Divide Two Integers
不得不说,这题目我根本没有读懂题目含义,然后看的题解才知道他要干什么。
就是让我们仅仅使用加减法,算出来除数,为了优化时间复杂度,这里就是用了倍增算法
c++ 代码
| class Solution { |
| public: |
| int divide(int dividend, int divisor) { |
| typedef long long LL; |
| bool is_minus = false; |
| if (dividend >= 0 && divisor < 0 || dividend <= 0 && divisor > 0) { |
| is_minus = true; |
| } |
| |
| |
| LL x = abs(LL(dividend)), y = abs(LL(divisor)); |
| LL res = 0LL; |
| vector<LL> v; |
| for (LL i = y; i <= x; i = i + i) { |
| v.push_back(i); |
| } |
| |
| for (int i = v.size() - 1; i >= 0; i -= 1) { |
| if (x >= v[i]) { |
| x -= v[i]; |
| res += (1LL << i); |
| } |
| } |
| if (is_minus) { |
| res = -res; |
| } |
| |
| if (res > (1LL << 31) - 1) { |
| return (1LL << 31) - 1; |
| } else if (res < -(1LL << 31)) { |
| return -(1LL << 31); |
| } else { |
| return res; |
| } |
| } |
| }; |
python 代码
| class Solution: |
| def divide(self, x: int, y: int) -> int: |
| is_minus = True if x >= 0 and y < 0 or x < 0 and y > 0 else False |
| x, y = abs(x), abs(y) |
| res = 0 |
| t = y |
| while x >= y: |
| t, i = y, 1 |
| while x >= t: |
| x -= t |
| res += i |
| t += t |
| i += i |
| if is_minus: |
| res = -res |
| |
| if res < -(2 ** 31): |
| return -(2 ** 31) |
| elif res > 2 ** 31 - 1: |
| return 2 ** 31 - 1 |
| else: |
| return res |
30. Substring with Concatenation of All Words
解题思路:
首先,对于每一个word,利用算法(可以KMP或者字符串Hash)查看他出现的位置
并存储在 vector pos(s.size())中
然后,然后我们使用滑动数组来动态查找匹配的内容
KMP + 滑动数组
因为字符串可以重复,我们还需要预处理出来重复的出字符串,进行字符串->idx 转化
C++ 代码
| class Solution { |
| public: |
| void kmp(string &s, string &p, vector<int> &ne, int idx, vector<int> &pos) { |
| ne[0] = ne[1] = 0; |
| int n = p.size(), j = 0, m = s.size(); |
| for (int i = 2; i < n; i ++ ) { |
| while (j && p[j + 1] != p[i]) j = ne[j]; |
| if (p[j + 1] == p[i]) j ++; |
| ne[i] = j; |
| } |
| j = 0; |
| for (int i = 1; i < m; i ++ ) { |
| while (j && p[j + 1] != s[i]) j = ne[j]; |
| if (p[j + 1] == s[i]) j += 1; |
| if (j == n - 1) { |
| pos[i - n + 2] = idx; |
| j = ne[j]; |
| } |
| } |
| } |
| |
| vector<int> findSubstring(string s, vector<string>& ps) { |
| |
| vector<int> res; |
| if (s.size() < ps.size() * ps[0].size()) { |
| return res; |
| } |
| |
| |
| int all_cnt = ps.size(); |
| unordered_map<string, int> tmp_m; |
| int j = 0; |
| vector<int> target(ps.size() + 10); |
| for (int i = 0; i < ps.size(); i ++ ) { |
| if (tmp_m.count(ps[i]) == 0) { |
| tmp_m[ps[i]] = j; |
| ps[j] = ps[i]; |
| target[j] = 1; |
| j ++; |
| } else { |
| target[tmp_m[ps[i]]] += 1; |
| } |
| } |
| int sz_tmp = ps.size(); |
| for (int i = j; i < sz_tmp; i ++ ) { |
| ps.pop_back(); |
| } |
| |
| |
| vector<int> pos(s.size() + 10); |
| vector<int> ne(s.size() + 10); |
| for (int i = 0; i < pos.size(); i ++ ) { |
| pos[i] = -1; |
| } |
| s = ' ' + s; |
| for (int i = 0; i < ps.size(); i ++ ){ |
| ps[i] = ' ' + ps[i]; |
| kmp(s, ps[i], ne, i, pos); |
| } |
| |
| |
| |
| int m = s.size() - 1, n = ps[0].size() - 1, k = ps.size(); |
| vector<int> cnt(k + 10); |
| for (int i = 1; i <= n; i ++ ) { |
| |
| for (int j = 0; j < k; j ++ ) |
| cnt[j] = 0; |
| int pre = -1, cur_cnt = 0;; |
| for (int j = i; j <= m; j += n) { |
| |
| if (pos[j] == -1) { |
| |
| if (pre != -1) { |
| for (int u = pre; u < j; u += n) { |
| cnt[pos[u]] = 0; |
| } |
| } |
| pre = -1, cur_cnt = 0; |
| } else { |
| if (cnt[pos[j]] == target[pos[j]]) { |
| for (int u = pre; u < j; u += n) { |
| if (pos[u] == pos[j]) { |
| cnt[pos[u]] -= 1; |
| pre = u + n; |
| cur_cnt -= 1; |
| break; |
| } else { |
| cur_cnt -= 1; |
| cnt[pos[u]] -= 1; |
| } |
| } |
| } |
| if (pre == -1) { |
| pre = j; |
| } |
| cnt[pos[j]] += 1; |
| cur_cnt += 1; |
| if (cur_cnt == all_cnt) { |
| res.push_back(pre - 1); |
| } |
| } |
| } |
| } |
| |
| return res; |
| } |
| }; |
python 代码
| class Solution: |
| s = '' |
| words = [] |
| pos = [] |
| ne = [] |
| |
| def kmp(self, t): |
| self.ne[0] = self.ne[1] = 0 |
| n, m = len(self.words[t]) - 1, len(self.s) - 1 |
| j = 0 |
| for i in range(2, n + 1): |
| while j != 0 and self.words[t][j + 1] != self.words[t][i]: |
| j = self.ne[j] |
| if self.words[t][j + 1] == self.words[t][i]: |
| j += 1 |
| self.ne[i] = j |
| j = 0 |
| for i in range(1, m + 1): |
| while j != 0 and self.words[t][j + 1] != self.s[i]: |
| j = self.ne[j] |
| if self.words[t][j + 1] == self.s[i]: |
| j += 1 |
| if j == n: |
| j = self.ne[j] |
| self.pos[i - n + 1] = t |
| |
| def findSubstring(self, s: str, words: List[str]) -> List[int]: |
| all_cnt = len(words) |
| n, m = len(words[0]), len(s) |
| |
| if m < n * len(words): |
| return [] |
| |
| |
| words.sort() |
| i, j, t = 1, 1, len(words) |
| cnt = [1 for i in range(t)] |
| for i in range(1, t): |
| if words[i] != words[i-1]: |
| words[j] = words[i] |
| j += 1 |
| else: |
| cnt[j - 1] += 1 |
| del words[j:t] |
| del cnt[j:t] |
| |
| |
| s = ' ' + s |
| for i in range(len(words)): |
| words[i] = ' ' + words[i] |
| t = len(words) |
| self.s, self.words = s, words |
| self.pos = [-1 for i in range(m + 10)] |
| self.ne = [-1 for i in range(m + 10)] |
| for i in range(t): |
| self.kmp(i) |
| |
| print(s) |
| print(cnt) |
| print(words) |
| print(self.pos) |
| |
| |
| res = [] |
| cur_cnt = [0 for i in range(m // n + 10)] |
| for i in range(1, n + 1): |
| j, pre = i, -1 |
| print(f'i = {i}') |
| for k in range(len(cur_cnt)): |
| cur_cnt[k] = 0 |
| for j in range(i, m + 1, n): |
| if self.pos[j] == -1: |
| if pre != -1: |
| k = pre |
| while k < j: |
| cur_cnt[self.pos[k]] = 0 |
| k += n |
| pre = -1 |
| else: |
| |
| if pre != -1 and cur_cnt[self.pos[j]] >= cnt[self.pos[j]]: |
| while self.pos[pre] != self.pos[j]: |
| cur_cnt[self.pos[pre]] -= 1 |
| pre += n |
| pre += n |
| else: |
| if pre == -1: |
| pre = j |
| cur_cnt[self.pos[pre]] += 1 |
| else: |
| cur_cnt[self.pos[j]] += 1 |
| if pre != -1 and all_cnt == 1 + (j - pre) // n: |
| res.append(pre - 1) |
| |
| return res |
Hash + 滑动数组
代码和 KMP 的差不多,仅仅是将 KMP部分换为了 HASH
| class Solution: |
| s = '' |
| words = [] |
| pos = [] |
| ne = [] |
| |
| def findSubstring(self, s: str, words: List[str]) -> List[int]: |
| BASE, MOD, A_NUM = 127, int(1e9+7), ord('a') |
| all_cnt = len(words) |
| n, m = len(words[0]), len(s) |
| |
| if m < n * len(words): |
| return [] |
| |
| |
| words.sort() |
| i, j, t = 1, 1, len(words) |
| cnt = [1 for i in range(t)] |
| for i in range(1, t): |
| if words[i] != words[i-1]: |
| words[j] = words[i] |
| j += 1 |
| else: |
| cnt[j - 1] += 1 |
| del words[j:t] |
| del cnt[j:t] |
| |
| |
| s = ' ' + s |
| for i in range(len(words)): |
| words[i] = ' ' + words[i] |
| t = len(words) |
| self.s, self.words = s, words |
| self.pos = [-1 for i in range(m + 10)] |
| str_to_number = {} |
| my_max_p = 1 |
| for i in range(1, n): |
| my_max_p = my_max_p * BASE % MOD |
| for i, p in enumerate(words): |
| cur_ord = 0 |
| for ch in p[1:]: |
| cur_ord = (cur_ord * BASE + ord(ch) - A_NUM) % MOD |
| str_to_number[cur_ord] = i |
| cur_ord = 0 |
| for i in range(1, m + 1): |
| cur_ord = (cur_ord * BASE + ord(s[i]) - A_NUM) % MOD |
| if i < n: |
| continue |
| elif i >= n: |
| if cur_ord in str_to_number.keys(): |
| self.pos[i - n + 1] = str_to_number[cur_ord] |
| else: |
| self.pos[i - n + 1] = -1 |
| cur_ord = cur_ord - my_max_p * (ord(s[i-n+1]) - A_NUM) |
| cur_ord %= MOD |
| cur_ord = cur_ord + MOD if cur_ord < 0 else cur_ord |
| |
| |
| print(s) |
| print(cnt) |
| print(words) |
| print(self.pos) |
| |
| |
| res = [] |
| cur_cnt = [0 for i in range(m // n + 10)] |
| for i in range(1, n + 1): |
| j, pre = i, -1 |
| print(f'i = {i}') |
| for k in range(len(cur_cnt)): |
| cur_cnt[k] = 0 |
| for j in range(i, m + 1, n): |
| if self.pos[j] == -1: |
| if pre != -1: |
| k = pre |
| while k < j: |
| cur_cnt[self.pos[k]] = 0 |
| k += n |
| pre = -1 |
| else: |
| |
| if pre != -1 and cur_cnt[self.pos[j]] >= cnt[self.pos[j]]: |
| while self.pos[pre] != self.pos[j]: |
| cur_cnt[self.pos[pre]] -= 1 |
| pre += n |
| pre += n |
| else: |
| if pre == -1: |
| pre = j |
| cur_cnt[self.pos[pre]] += 1 |
| else: |
| cur_cnt[self.pos[j]] += 1 |
| if pre != -1 and all_cnt == 1 + (j - pre) // n: |
| res.append(pre - 1) |
| |
| return res |
【推荐】国内首个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)