回溯算法习题其二-Java【力扣】【算法学习day.16】

前言

###我做这类文档一个重要的目的还是给正在学习的大家提供方向(例如想要掌握基础用法,该刷哪些题?)我的解析也不会做的非常详细,只会提供思路和一些关键点,力扣上的大佬们的题解质量是非常非常高滴!!!


习题

1.非递增子序列

题目链接: 491. 非递减子序列 - 力扣(LeetCode)

题面:

基本分析: 回溯暴力,可以维护一个set进行一些小剪枝

代码:

java 复制代码
class Solution {

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

        dfs(nums, -1, new ArrayList<>());
        return res;
    }

    private void dfs(int[] nums, int idx, List<Integer> curList) {
  
        if (curList.size() > 1) {
            res.add(new ArrayList<>(curList));
        }


        Set<Integer> set = new HashSet<>();
        for (int i = idx + 1; i < nums.length; i++) {
        
            if (set.contains(nums[i])) { 
                continue;
            }
            set.add(nums[i]);
        
            if (idx == -1 || nums[i] >= nums[idx]) {
                curList.add(nums[i]);
                dfs(nums, i, curList);
                curList.remove(curList.size() - 1);
            }
        }
    }
}

2.全排列

题目链接: 46. 全排列 - 力扣(LeetCode)

题面:

**基本分析:**在上一题的基础上维护一个数组来记录元素是否被使用

代码:

java 复制代码
class Solution {
    List<List<Integer>> list = new ArrayList<>();
    int len;
    public List<List<Integer>> permute(int[] nums) {
        len = nums.length-1;
        List<Integer> stack = new ArrayList<>();
        int[] arr = new int[len+1];
        recursion(nums,stack,arr);
        return list;
    }

    public void recursion(int[] nums,List<Integer> stack,int[] arr){
        if(stack.size()==len+1){
            list.add(new ArrayList<>(stack));
        }
        for(int i = 0;i<=len;i++){
            if(arr[i]==0){
                arr[i]=1;
                stack.add(nums[i]);
                recursion(nums,stack,arr);
                arr[i]=0;
                stack.remove(stack.size()-1);
            }
        }
    }
}

3.全排列II

题目链接: 47. 全排列 II - 力扣(LeetCode)

题面:

**基本分析:**元素重复导致重复答案,利用set去重

代码:

java 复制代码
class Solution {
    Set<List<Integer>> list = new HashSet<>();
    int len;
    public List<List<Integer>> permuteUnique(int[] nums) {
        len = nums.length-1;
        List<Integer> stack = new ArrayList<>();
        int[] arr = new int[len+1];
        recursion(nums,stack,arr);
        return new ArrayList<>(list);
    }
    public void recursion(int[] nums,List<Integer> stack,int[] arr){
        if(stack.size()==len+1){
            list.add(new ArrayList<>(stack));
        }
        for(int i = 0;i<=len;i++){
            if(arr[i]==0){
                arr[i]=1;
                stack.add(nums[i]);
                recursion(nums,stack,arr);
                arr[i]=0;
                stack.remove(stack.size()-1);
            }
        }
    }
}

4.重新安排行程

题目链接: 332. 重新安排行程 - 力扣(LeetCode)

题面:

基本分析: 对list排序和回溯暴力会超时最后一个样例 ,但是排序必不可少,参照下面这位的做法:

代码:

java 复制代码
class Solution {
    List<String> ans = new ArrayList<>();
    Map<String, TreeMap<String, Integer>> map = new HashMap<>();

    public List<String> findItinerary(List<List<String>> tickets) {
        for (List<String> list : tickets) {
            String start = list.get(0);
            TreeMap<String, Integer> tmap = map.getOrDefault(start, new TreeMap<>());
            String end = list.get(1);
            int sum = tmap.getOrDefault(end, 0) + 1;
            tmap.put(end, sum);
            map.put(start, tmap);
        }
        ans.add("JFK");
        try {
            recursion(tickets.size() + 1);
        } catch (RuntimeException e) {
        }
        System.out.println(tickets.size());
        System.out.println(ans.size());
        return ans;
    }

    public void recursion(int n) {
        if (ans.size() == n)throw new RuntimeException();
        String start = ans.getLast();
        if(map.containsKey(start)){
            for (Map.Entry<String, Integer> entry : map.get(start).entrySet()) {
            int count = entry.getValue();
            if (count > 0) {
                ans.add(entry.getKey());
                entry.setValue(count - 1);
                recursion(n);
                entry.setValue(count);
                ans.removeLast();
            }
        }
        }
    }
}

后言

上面是回溯算法的基本概念和部分习题,下一篇会讲解回溯算法的其他相关力扣习题,希望有所帮助,一同进步,共勉!

相关推荐
秋说8 分钟前
【PTA数据结构 | C语言版】两枚硬币
c语言·数据结构·算法
二十雨辰10 分钟前
[尚庭公寓]07-Knife快速入门
java·开发语言·spring
qq_5139704420 分钟前
力扣 hot100 Day37
算法·leetcode
掉鱼的猫21 分钟前
Java MCP 实战:构建跨进程与远程的工具服务
java·openai·mcp
不見星空40 分钟前
leetcode 每日一题 1865. 找出和为指定值的下标对
算法·leetcode
我爱Jack1 小时前
时间与空间复杂度详解:算法效率的度量衡
java·开发语言·算法
米饭「」1 小时前
C++AVL树
java·开发语言·c++
Zonda要好好学习1 小时前
Python入门Day4
java·网络·python
☆璇1 小时前
【数据结构】栈和队列
c语言·数据结构
SimonKing1 小时前
告别传统读写!RandomAccessFile让你的Java程序快人一步
java·后端·程序员