LeetCode 21-30题

 

正文

本博客记录的是 LeetCode 21 到 30 题的题解

之前很少使用的语法

# 21 Merge k Sorted Lists
# 由两种纯暴力做法和两种对应的优化算法
# 堆可以优化快速查找最小值,二分可以优化合并的深度
# 二分一定要要注意递归的终点,l == r, l > r都是出来的
# python 中的堆讲解 这个模块名为heapq(其中的q表示队列
# heappush(heap, val), val = heappop(heap)
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
# 28 python 字符串Hash
h[i] = (h[i - 1] * BASE + ord(s[i])) % MOD
# 29 加分的二进制倍增算法
# 30 非常容易出Bug的地方,因为ps.size()会变化
for (int i = j; i < ps.size(); i ++ ) {
ps.pop_back();
}

21. Merge Two Sorted Lists

直接就是使用 头结点 dummy,然后进行指针移动即可。

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* 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 代码

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode()
cur = dummy
while list1 or list2:
if not list1: # list1 is None
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

纯暴力做法

/**
* 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* 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++ 代码

/**
* 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) {}
* };
*/
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 代码

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
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(k1)+n2(k1)+n3(k2)+n4(k3)+...+nk12+nk

那么,我们现在使用二分合并的思想(有点像归并排序)进行求解
一定要记得归并的递归终点
len == 1
len == 0

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
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
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = 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++ 代码

/**
* 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* 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代码

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
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

使用数组交换指针

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
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

再来一种

# Definition for singly-linked list.
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++ 代码

/*
个人感觉,要么是字符串hash,要么是 KMP算法解决
*/
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;
}
// Hash 判断 m - n --> m - 1 len: n
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
# hash
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
# match
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;
// initial
int m = haystack.size(), n = needle.size();
haystack = " " + haystack, needle = " " + needle;
// kmp
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;
}
}
// match
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
# KMP
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
# Match
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,否则容易溢出
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) { // successful match
pos[i - n + 2] = idx;
j = ne[j];
}
}
}
vector<int> findSubstring(string s, vector<string>& ps) {
// 处理特殊情况 special judge
vector<int> res;
if (s.size() < ps.size() * ps[0].size()) {
return res;
}
// 我们预处理ps,去除重复的元素,并统计他的目标数量
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();
}
// initial and kmp
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 ++ ) { // 需要按照类别滑动n次,相当于模 n 剩余类
// printf("i=%d->n=%d\n", i, n);
for (int j = 0; j < k; j ++ )
cnt[j] = 0;
int pre = -1, cur_cnt = 0;;
for (int j = i; j <= m; j += n) { // 以 n 为步长,进行滑动窗口
// printf("j=%d, pos[%d]=%d, pre=%d\n", j, j, pos[j], pre);
if (pos[j] == -1) {
// cnt 清空
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)
# special judge
if m < n * len(words):
return []
# words initialize
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]
# kmp
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)
# Sliding interval
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)
# special judge
if m < n * len(words):
return []
# words initialize
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]
# hash
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): # n - 1 times
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)
# Sliding interval
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
posted @   lucky_light  阅读(65)  评论(0编辑  收藏  举报
编辑推荐:
· 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)
点击右上角即可分享
微信分享提示