最短回文串

 

目录

LeetCode214 最短回文串

leetcode209 长度最小的子数组

leetcode216组合总和 III


 

LeetCode214 最短回文串

 因此s1也是回文串,要找到最短的s^,,等价于找到最长的s1 ,换言之,需要在字符串s中找出一个最长的前缀s1,它是一个回文串,找到s1之后,剩余的部分s2的反序就是结果s^,

如果使用暴力方法,会超时

利用Rabin-Karp字符串哈希算法来找出最长的回文串

  • 在该方法中,我们将字符串看成一个 base 进制的数,它对应的十进制值就是哈希值。显然,两个字符串的哈希值相等,当且仅当这两个字符串本身相同。然而如果字符串本身很长,其对应的十进制值在大多数语言中无法使用内置的整数类型进行存储。因此,我们会将十进制值对一个大质数 mod行取模。此时:
  • 如果两个字符串的哈希值在取模后不相等,那么这两个字符串本身一定不相同;
  • 如果两个字符串的哈希值在取模后相等,并不能代表这两个字符串本身一定相同。例如两个字符串的哈希值分别为 2 和 15,模数为 13,虽然 2\equiv 15(mod 13),但它们不相同。

一般来说,我们选取一个大于字符集大小(即字符串中可能出现的字符种类的数目)的质数作为base ,再选取一个在字符串长度平方级别左右的质数作为 mod,产生哈希碰撞的概率就会很低。

算法如下:

一个字符串是回文串,当且仅当该字符串与它的反序相同。因此,我们仍然暴力地枚举s_1和它的反序的哈希值

设当前枚举到的结束位置为i,对应的s_1记为s_1^i,其反序记为 \hat s_1^i,,我们可以通过递推的方式,在O(1)时间计算其对对应的值

\\hash(s_1^i)=hash(s_1^{i-1})\times base + ASCII(s[i])\\ hash(\hat s _1^i)=hash(\hat s_1^{i-1}) + ASCII(s[i]) \times base ^ i

其中ASCII(x)表示字符xASCII码。主要需要将结果对mod取模

如果hash(s_1^i)=hash(\hat s_1^{i}),那么s_1^i就是一个回文串,剩下的字符串的反序即为返回的结果值

代码如下:

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;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值