Leetcode刷题记录(回溯法)

回溯法

回溯法公式

result = []
def backtrack(路径, 选择列表):
    if 满足结束条件:
        result.add(路径)
        return
    
    for 选择 in 选择列表:
        做选择
        backtrack(路径, 选择列表)
        撤销选择

这个故事还是从全排列说起

class Solution {
    private List<List<Integer>> res = new ArrayList<>();
    private List<Integer> com = new ArrayList<>();
    public List<List<Integer>> permute(int[] nums) {
        int count = nums.length;
        int[] flag = new int[count];
        for(int i =0;i<count;i++)
        {
            flag[i] = 0;
        }
        backtrack(nums,flag,0,count);
        return res;
    }
    private void backtrack(int[] nums,int[] flag,int first,int end)
    {
        if(first == end)
        {
            res.add(new ArrayList<>(com));
            return;
        }
        for(int i=0;i<end;i++)
        {
            if(flag[i] == 1)
            continue;
            flag[i] = 1;
            com.add(nums[i]);
            backtrack(nums,flag,first+1,end);
            com.remove(com.size()-1);
            flag[i] = 0;
        }
    }
}

交换法交换法,我觉得交换法比标记法更容易理解,不懂的时候调试一波

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();

        List<Integer> output = new ArrayList<Integer>();
        for (int num : nums) {
            output.add(num);
        }
        int n = nums.length;
        backtrack(n, output, res, 0);
        return res;
    }
    public void backtrack(int n, List<Integer> output, List<List<Integer>> res, int first) {
        // 所有数都填完了
        if (first == n) {
            res.add(new ArrayList<Integer>(output));
        }
        for (int i = first; i < n; i++) {
            // 动态维护数组
            Collections.swap(output, first, i);
            // 继续递归填下一个数
            backtrack(n, output, res, first + 1);
            // 撤销操作
            Collections.swap(output, first, i);
        }
    }
}

开心呢字符串,真的很不开心,思想和全排列类似,注意不需要保存数组

class Solution
{
    String res = "";
    int index = 0;
    public String getHappyString(int n,int k)
    {
        StringBuilder sb = new StringBuilder();
        BackTrack(sb,n,k);
        return res;
    }
    public void BackTrack(StringBuilder sb,int n,int k)
    {
        if(index>=k)
            return;
        int len = sb.length();
        if(len == n)
        {
            index++;
            if(index==k)
            {
                res = sb.toString();
            }
            return;
        }

        for(int i =0;i<3;i++)
        {
            if(len>0&&sb.charAt(len-1)==(char)('a'+i))
            continue;//查重

            sb.append((char)('a'+i));
            BackTrack(sb,n,k);
            sb.deleteCharAt(len);
        }
    }
}

分割回文串
做这道题的时候,顺便还能把动态规划复习一遍,回溯法大体是上面的那个思路,理清集合之间的关系就好了

class Solution {

    public List<List<String>> partition(String s) {
        char[] chars = s.toCharArray();
        int n = chars.length;
        //System.out.println(n);
        boolean [][]dp = new boolean[n][n];
        //下面的两个循环结构已经找出了所有的回文串了
        for(int i =0;i<n;i++)
        {
            dp[i][i] = true;
        }
        for(int j=1;j<n;j++)
        {
            for(int i =0;i<j;i++)
            {
                dp[i][j] = (chars[i] == chars[j])&&((j-i<=2)||(dp[i+1][j-1]));
            }
        }
        List<List<String>> list = new ArrayList<>();
        BackTrack(0,n,s,dp,new ArrayList<>(),list);
        return list;
    }
    public void BackTrack(int _start,int _end,String s,boolean[][] dp,List<String> tmp,List<List<String>> list)
    {
        if(_start>=_end)
        {
            list.add(new ArrayList<>(tmp));
            return;
        }
        boolean[] dp1 = dp[_start];
        for(int i = _start;i<_end;i++)
        {
            if(dp1[i])
            {
                tmp.add(s.substring(_start,i+1));
                BackTrack(i+1,_end,s,dp,tmp,list);
                tmp.remove(tmp.size()-1);
            }
        }
        return ;
    }
}

单词拆分2

class Solution {
    private List<String> list;
    public List<String> wordBreak(String s, List<String> wordDict) {
        if(s==null||s.length() == 0)
           return list;
        if(wordDict==null|wordDict.size()==0)
        return list;
        Map<Integer, List<List<String>>> map = new HashMap<Integer, List<List<String>>>();
        List<List<String>> wordBreaks = backtrack(s, s.length(), new HashSet<String>(wordDict), 0, map);
        List<String> list = new LinkedList<String>();
        if(!check(s,wordDict))
           return list;
        for (List<String> wordBreak : wordBreaks) {
            list.add(String.join(" ", wordBreak));
        }
        return list;
    }

    public List<List<String>> backtrack(String s, int length, Set<String> wordSet, int index, Map<Integer, List<List<String>>> map) {
        if (!map.containsKey(index)) {
            List<List<String>> wordBreaks = new LinkedList<List<String>>();
            if (index == length) {
                wordBreaks.add(new LinkedList<String>());
            }
            for (int i = index + 1; i <= length; i++) {
                String word = s.substring(index, i);
                if (wordSet.contains(word)) {
                    List<List<String>> nextWordBreaks = backtrack(s, length, wordSet, i, map);
                    for (List<String> nextWordBreak : nextWordBreaks) {
                        LinkedList<String> wordBreak = new LinkedList<String>(nextWordBreak);
                        wordBreak.offerFirst(word);
                        wordBreaks.add(wordBreak);
                    }
                }
            }
            map.put(index, wordBreaks);
        }
        return map.get(index);
    }
    private boolean check(String s,List<String> wordDict)
    {
        boolean [] dp = new boolean[s.length()+1];
        dp[0] = true;
        for(int i=1;i<=s.length();i++)
        {
            for(int j=0;j<i;j++)
            {
                String str = s.substring(j,i);
                if(dp[j]&&wordDict.contains(str))
                {
                    dp[i]=true;
                    break;
                }
            }
        }
        return dp[s.length()];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值