目录
LeetCode214 最短回文串
因此s1也是回文串,要找到最短的,等价于找到最长的s1 ,换言之,需要在字符串s中找出一个最长的前缀s1,它是一个回文串,找到s1之后,剩余的部分s2的反序就是结果
如果使用暴力方法,会超时
利用Rabin-Karp字符串哈希算法来找出最长的回文串
- 在该方法中,我们将字符串看成一个 进制的数,它对应的十进制值就是哈希值。显然,两个字符串的哈希值相等,当且仅当这两个字符串本身相同。然而如果字符串本身很长,其对应的十进制值在大多数语言中无法使用内置的整数类型进行存储。因此,我们会将十进制值对一个大质数 行取模。此时:
- 如果两个字符串的哈希值在取模后不相等,那么这两个字符串本身一定不相同;
- 如果两个字符串的哈希值在取模后相等,并不能代表这两个字符串本身一定相同。例如两个字符串的哈希值分别为 2 和 15,模数为 13,虽然 ,但它们不相同。
一般来说,我们选取一个大于字符集大小(即字符串中可能出现的字符种类的数目)的质数作为 ,再选取一个在字符串长度平方级别左右的质数作为 ,产生哈希碰撞的概率就会很低。
算法如下:
一个字符串是回文串,当且仅当该字符串与它的反序相同。因此,我们仍然暴力地枚举和它的反序的哈希值
设当前枚举到的结束位置为,对应的记为,其反序记为 ,我们可以通过递推的方式,在O(1)时间计算其对对应的值
其中表示字符的码。主要需要将结果对取模
如果,那么就是一个回文串,剩下的字符串的反序即为返回的结果值
代码如下:
class Solution {
public String shortestPalindrome(String s) {
if(s == null || s.length() == 0){
return "";
}
int n = s.length();
int base = 131, mod = 1000000007;
int mul = 1, left = 0, right = 0;
int best = -1;
for(int i = 0; i < n; i ++){
left = (int)(((long)base * left + s.charAt(i)) % mod);
right = (int)((right + (long)mul * s.charAt(i))%mod);
if(left == right){
best = i;
}
mul = (int) ((long)mul * base % mod);
}
String addReverse = best == n - 1 ? "" : s.substring(best + 1);
String add = new StringBuilder(addReverse).reverse().toString();
return add + s;
}
}
leetcode209 长度最小的子数组
算法:
先利用一个sum数字计算连续和,再利用快慢指针,left 和right
初始化都为0
计算区间[left,right]之间的数字和:sums[right] - sums[left] + nums[left]
- 如果和小于s, right ++
- 否则,判断区间大小right - left + 1是否比目前最短长度小,是的话直接更新,同时left ++
整个过程中,right和left一种都是往右移动
class Solution {
public int minSubArrayLen(int s, int[] nums) {
if(nums == null || nums.length == 0){
return 0;
}
if(nums.length == 1 && nums[0] < s){
return 0;
}
int len = nums.length;
int[] sum = new int[len];
int ans = Integer.MAX_VALUE;
sum[0] = nums[0];
for(int i = 1; i < len; i++){
sum[i] = sum[i-1] + nums[i];
}
int left = 0,right = 0;
while(left < len && right < len){
int sumTmp = sum[right] - sum[left] + nums[left];
if(sumTmp < s){
right ++;
}
else{
if(right - left + 1 < ans){
ans = right - left + 1;
}
left ++;
}
}
return ans == Integer.MAX_VALUE ? 0 : ans;
}
}
leetcode216组合总和 III
算法:直接回溯
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> combinationSum3(int k, int n) {
dfs(new ArrayList<>(), k, n, 1);
return res;
}
public void dfs(List<Integer> resElement, int k, int n, int start){
if(resElement.size() == k){
if(getSum(resElement) == n){
res.add(new ArrayList(resElement));
return;
}
}
//表示没有数可以再加了,直接返回
if(start == 10){
return;
}
//当前数加入结果集中
resElement.add(start);
dfs(resElement, k, n, start + 1);
resElement.remove(resElement.size() - 1);
//当前数不加入结果集中
dfs(resElement, k, n, start + 1);
}
public int getSum(List<Integer> nums){
int sum = 0;
for(int i =0; i < nums.size(); i++){
sum += nums.get(i);
}
return sum;
}
}