Leetcode每日刷题:回溯算法&(字符串+数组)

1.回溯:组合总和

在这里插入图片描述

class Solution {
    List<List<Integer>> res=new LinkedList<>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        if(candidates==null || candidates.length==0){
            return res;
        }
        LinkedList<Integer> track=new LinkedList<>();
        backTrack(candidates,target,track,0,0);
        return res;
    }
    public void backTrack(int[] candidates, int target,LinkedList<Integer> track,int sum,int start){
        if(sum==target){
            res.add(new LinkedList(track));
            return;
        }
        for(int i=start;i<candidates.length;i++){
            if(sum+candidates[i]<=target){
                track.add(candidates[i]);
                sum+=candidates[i];
                backTrack(candidates,target,track,sum,i);
                track.removeLast();
                sum-=candidates[i];
            }
        }
    }
}

2.回溯:字符串的排列

在这里插入图片描述

class Solution {
    Set<String> set=new HashSet<>();
    public String[] permutation(String s) {
        if(s==null || s.length()==0){
            return new String[0];
        }
        StringBuilder sb=new StringBuilder();
        boolean[] used=new boolean[s.length()];
        backTrack(s,sb,used);
        String[] res=new String[set.size()];
        int index=0;
        for(String s1:set){
            res[index]=s1;
            index++;
        }
        return res;
    }
    public void backTrack(String s,StringBuilder sb,boolean[] used){
        if(sb.length()==s.length()){
            set.add(new String(sb.toString()));
            return;
        }
        for(int i=0;i<s.length();i++){
            if(used[i]) continue;
            sb.append(s.charAt(i));
            used[i]=true;
            backTrack(s,sb,used);
            sb.deleteCharAt(sb.length()-1);
            used[i]=false;
        }
    }
}

3.回溯:组合总和2

在这里插入图片描述

class Solution {
    List<List<Integer>> res=new LinkedList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        if(candidates==null || candidates.length==0){
            return res;
        }
        LinkedList<Integer> track=new LinkedList<>();
        boolean[] used=new boolean[candidates.length];
        Arrays.sort(candidates);
        backTrack(candidates,target,track,0,0,used);
        return res;
    }
    public void backTrack(int[] candidates, int target,LinkedList<Integer> track,int start,int sum,boolean[] used){
        if(sum==target){
            res.add(new LinkedList(track));
            return;
        }
        for(int i=start;i<candidates.length;i++){
            if(i>0 && candidates[i-1]==candidates[i] && !used[i-1]){
                continue;
            }
            if(sum+candidates[i]<=target){
                track.add(candidates[i]);
                sum+=candidates[i];
                used[i]=true;
                backTrack(candidates,target,track,i+1,sum,used);
                track.removeLast();
                sum-=candidates[i];
                used[i]=false;
            }
        }
    }
}

4.回溯:分割回文串

在这里插入图片描述

class Solution {
    List<List<String>> res=new LinkedList<>();
    public List<List<String>> partition(String s) {
        if(s==null || s.length()==0){
            return res;
        }
        LinkedList<String> track=new LinkedList<>();
        backTrack(s,track,0);
        return res;
    }
    //count用于统计已经加进track里面的字符的总个数,用于判断是否当前track已经满足加进res的条件
    public void backTrack(String s,LinkedList<String> track,int index){
        if(index==s.length()){
            res.add(new LinkedList(track));
            return;
        }
        for(int i=index;i<s.length();i++){
            if(!isHuiWen(s,index,i)){
                continue;
            }
            track.add(s.substring(index,i+1));
            backTrack(s,track,i+1);
            track.removeLast();
        }
    }
    public boolean isHuiWen(String s,int left,int right){
        while(left<right){
            if(s.charAt(left)!=s.charAt(right)){
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

5.回溯:所有可能的路径

在这里插入图片描述

class Solution {
    List<List<Integer>> res=new LinkedList<>();
    public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
        if(graph==null || graph.length==0){
            return res;
        }
        LinkedList<Integer> track=new LinkedList<>();
        backTrack(0,graph,track);
        return res;
    }
    public void backTrack(int index,int[][] graph,LinkedList<Integer> track){
        track.add(index);//index是下一个要访问的值
        //如果index恰好等于n-1,则这是一条能够到达n-1的路径,则将这条路径添加到结果列表中
        if(index==graph.length-1){
            res.add(new LinkedList(track));
            return;
        }
        //比如已经添加了值为2的节点,即index=2,那么接下来就要去遍历值为2那个节点所能到达的位置,判断其能否到达终点
        for(int i=0;i<graph[index].length;i++){
            backTrack(graph[index][i],graph,track);
            track.removeLast();
        }
    }
}

6.回溯:子集2

在这里插入图片描述

class Solution {
    List<List<Integer>> res=new LinkedList<>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        if(nums==null || nums.length==0){
            return res;
        }

        //遇到这种带有重复值的,解集中不能重复的,则需要先排序,并定义一个used数组记录使用过的位置,后续再进行剪枝
        Arrays.sort(nums);
        boolean[] used=new boolean[nums.length];
        LinkedList<Integer> track=new LinkedList<>();
        //需要一个位置索引start限制下次遍历从下个位置开始
        backTrack(nums,track,0,used);
        return res;
    }
    public void backTrack(int[] nums,LinkedList<Integer> track,int start,boolean[] used){
        res.add(new LinkedList(track));
        for(int i=start;i<nums.length;i++){
            //遇到重复值跳过
            if(i>0 && nums[i-1]==nums[i] && !used[i-1]){
                continue;
            }
            track.add(nums[i]);
            used[i]=true;
            backTrack(nums,track,i+1,used);
            track.removeLast();
            used[i]=false;
        }
    }
}

7.回溯:不同路径3

在这里插入图片描述
在这里插入图片描述

class Solution {
    int res=0;
    public int uniquePathsIII(int[][] grid) {
        if(grid==null || grid.length==0){
            return res;
        }
        //记录走过哪些位置,不要重复走
        boolean[][] used=new boolean[grid.length][grid[0].length];
        //找到起始位置
        int start_i=0,start_j=0;
        //0的个数num_zero,从起点到终点走的步数应该是num_zero+1
        int num_zero=0;
        for(int i=0;i<grid.length;i++){
            for(int j=0;j<grid[0].length;j++){
                if(grid[i][j]==1){
                    start_i=i;
                    start_j=j;
                }
                if(grid[i][j]==0){
                    num_zero++;
                }
            }
        }
        //从起始位置开始递归遍历
        backTrack(grid,used,start_i,start_j,num_zero,0);
        return res;
    }
    //(i,j)表示正在遍历的位置,step为走过的步数
    public void backTrack(int[][] grid,boolean[][] used,int i,int j,int num_zero,int step){
        //1.进行当前位置合法性判断
        if(i<0 || j<0 || i>=grid.length || j>=grid[0].length || used[i][j] || grid[i][j]==-1){
            return;
        }
        //2.判断是否到达终点,如果到达,则是一个有效路径,res+1
        if(grid[i][j]==2 && step==num_zero+1){
            res++;
            return;
        }
        //3.走到当前位置,然后对当前位置的四个方向进行递归
        used[i][j]=true;
        backTrack(grid,used,i+1,j,num_zero,step+1);
        backTrack(grid,used,i,j+1,num_zero,step+1);
        backTrack(grid,used,i-1,j,num_zero,step+1);
        backTrack(grid,used,i,j-1,num_zero,step+1);
        used[i][j]=false;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
KMP算法是一种字符串匹配算法,用于在一个文本串S内查找一个模式串P的出现位置。它的时间复杂度为O(n+m),其中n为文本串的长度,m为模式串的长度。 KMP算法的核心思想是利用已知信息来避免不必要的字符比较。具体来说,它维护一个next数组,其中next[i]表示当第i个字符匹配失败时,下一次匹配应该从模式串的第next[i]个字符开始。 我们可以通过一个简单的例子来理解KMP算法的思想。假设文本串为S="ababababca",模式串为P="abababca",我们想要在S中查找P的出现位置。 首先,我们可以将P的每个前缀和后缀进行比较,得到next数组: | i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | --- | - | - | - | - | - | - | - | - | | P | a | b | a | b | a | b | c | a | | next| 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 | 接下来,我们从S的第一个字符开始匹配P。当S的第七个字符和P的第七个字符匹配失败时,我们可以利用next[6]=4,将P向右移动4个字符,使得P的第五个字符与S的第七个字符对齐。此时,我们可以发现P的前五个字符和S的前五个字符已经匹配成功了。因此,我们可以继续从S的第六个字符开始匹配P。 当S的第十个字符和P的第八个字符匹配失败时,我们可以利用next[7]=1,将P向右移动一个字符,使得P的第一个字符和S的第十个字符对齐。此时,我们可以发现P的前一个字符和S的第十个字符已经匹配成功了。因此,我们可以继续从S的第十一个字符开始匹配P。 最终,我们可以发现P出现在S的第二个位置。 下面是KMP算法的C++代码实现:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值