目录
重点看:28,32
没意思:38
LC_28.实现 strStr() *
方法一:子串逐一比较 - 线性时间复杂度
最直接的方法 - 沿着主串逐步移动滑动窗口,将窗口内的子串与 needle 字符串比较。(窗口大小=子串长度)
方法二:双指针 - 线性时间复杂度
上一个方法的缺陷是会将 haystack 所有长度为 L 的子串都与 needle 字符串比较,实际上是不需要这么做的。
首先,只有子串的第一个字符跟 needle 字符串第一个字符相同的时候才需要比较
其次,可以一个字符一个字符比较,一旦不匹配了就立刻终止。
方法三: Rabin Karp - 常数复杂度
有一种最坏时间复杂度也为 O(N) 的算法。思路是这样的,先生成窗口内子串的哈希码,然后再跟 needle 字符串的哈希码做比较。
这个思路有一个问题需要解决,如何在常数时间生成子串的哈希码?
滚动哈希:常数时间生成哈希码
生成一个长度为 L 数组的哈希码,需要 O(L) 时间。
如何在常数时间生成滑动窗口数组的哈希码?利用滑动窗口的特性,每次滑动都有一个元素进,一个出。
由于只会出现小写的英文字母,因此可以将字符串转化成值为 0 到 25 的整数数组: arr[i] = (int)S.charAt(i) - (int)'a'。按照这种规则,abcd 整数数组形式就是 [0, 1, 2, 3],转换公式如下所示。
可以将上面的公式写成通式,如下所示。其中 ci 为整数数组中的元素,a = 26,其为字符集的个数
下面来考虑窗口从 abcd 滑动到 bcde 的情况。这时候整数形式数组从 [0, 1, 2, 3] 变成了 [1, 2, 3, 4],数组最左边的 0 被移除,同时最右边新添了 4。滑动后数组的哈希值可以根据滑动前数组的哈希值来计算,计算公式如下所示。
如何避免溢出
a^L 可能是一个很大的数字,因此需要设置数值上限来避免溢出。设置数值上限可以用取模的方式,即用 h % modulus 来代替原本的哈希值。
理论上,modules 应该取一个很大数,但具体应该取多大的数呢? 详见这篇文章,对于这个问题来说 2^{31} 就足够了。
感觉理解起来还是很简单的,很实用啊
LC_32. 最长有效括号 H*
暴力枚举偶数长度的子串,用stack判断是否有效
public class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<Character>();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
stack.push('(');
} else if (!stack.empty() && stack.peek() == '(') {
stack.pop();
} else {
return false;
}
}
return stack.empty();
}
public int longestValidParentheses(String s) {
int maxlen = 0;
for (int i = 0; i < s.length(); i++) {
for (int j = i + 2; j <= s.length(); j+=2) {
if (isValid(s.substring(i, j))) {
maxlen = Math.max(maxlen, j - i);
}
}
}
return maxlen;
}
}
用stack模拟 O(n)
public class Solution {
public int longestValidParentheses(String s) {
int maxans = 0;
Stack<Integer> stack = new Stack<>();
stack.push(-1);
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
stack.push(i);
} else {
stack.pop();
if (stack.empty()) {
stack.push(i);
} else {
maxans = Math.max(maxans, i - stack.peek());
}
}
}
return maxans;
}
}
38. 外观数列 E
「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。前五项如下:
1. 1
2. 11
3. 21
4. 1211
5. 111221
1 被读作 "one 1" ("一个一") , 即 11。
11 被读作 "two 1s" ("两个一"), 即 21。
21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出外观数列的第 n 项。
注意:整数序列中的每一项将表示为一个字符串。
打表 ,n<=30
class Solution {
public:
string countAndSay(int n) {
int i=1;
string s="1";
while(i<n){
string tmp="";
int num=1;
for(int j=1;j<s.length();j++){
if(s[j-1]==s[j]){
num++;
} else{
tmp+=to_string(num);
tmp+=s[j-1];
num=1;
}
}
tmp+=to_string(num);//对出现在末尾的连续数字结果尚未保存
tmp+=s[s.length()-1];
s=tmp;
i++;
}
return s;
}
};
来源:CSDN
作者:weixin_43107805
链接:https://blog.csdn.net/weixin_43107805/article/details/104883351