当前位置:网站首页>Day10/11 递归 / 回溯

Day10/11 递归 / 回溯

2022-06-10 14:51:00 寄生于黑暗中的光

1 21. 合并两个有序链表

1.1 题目

在这里插入图片描述

1.2 题解

/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */
class Solution {
    
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
    

        if(list1 == null)
            return list2;
        if(list2 == null)
            return list1;

        ListNode mergeList = new ListNode();
        ListNode res = mergeList;
        ListNode p = list1;
        ListNode q = list2;

        while(p != null && q != null){
    
            if(p.val < q.val){
    
                mergeList.next = p;
                mergeList = mergeList.next;
                p = p.next;
            }else{
    
                mergeList.next = q;
                mergeList = mergeList.next;
                q = q.next;
            }
        }

        if(p == null && q == null)
            return res;

        while(p != null){
    
            mergeList.next = p;
            mergeList = mergeList.next;
            p = p.next;
        }

        while(q != null){
    
            mergeList.next = q;
            mergeList = mergeList.next;
            q = q.next;
        }

        return res.next;
    }
}

注:自己采用的归并的思想,但是这道题本身还是以递归的思路去做较为合适,这篇文章的题解很好。

2 206. 反转链表

2.1 题目

在这里插入图片描述

2.2 题解

/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */
class Solution {
    
    public ListNode reverseList(ListNode head) {
    
        if(head == null)
            return head;
        
        ListNode p = new ListNode(head.val, null);
        while(head.next != null){
    
            ListNode q = new ListNode(head.next.val, null);
            q.next = p;
            p = q;
            head = head.next;
        }

        return p;
    }
}

注:第一想法就是头插法,也实现了;看了下题解,递归好重要。

3 77. 组合

3.1 题目

在这里插入图片描述

3.2 题解

class Solution {
    
    public List<List<Integer>> combine(int n, int k) {
    
        List<List<Integer>> res = new ArrayList<>();

        if(k <= 0 || k > n)
            return res;

        // 从1开始搜索
        Deque<Integer> path = new ArrayDeque<>();
        dfs(n, k, 1, path, res);
        return res;
    }

    private void dfs(int n, int k, int begin, Deque<Integer> path, List<List<Integer>> res){
    
        // 确定递归的终止条件:栈内长度达到组合长度时
        if(path.size() == k){
    
            res.add(new ArrayList<>(path));
            return;
        }

        // 遍历所有的搜索起点
        for(int i = begin; i <= n - (k - path.size()) + 1; i++){
    
            // 向路径变量中添加一个数
            path.addLast(i);
            // 下一轮搜索,设置的搜索起点要加 1,因为组合数理不允许出现重复的元素
            dfs(n, k, i + 1, path, res);
            // 重点理解这里:深度优先遍历有回头的过程,因此递归之前做了什么,递归之后需要做相同操作的逆向操作
            path.removeLast();
        }
    }
}

注:这个大佬的回溯题解好好学。

4 46. 全排列

4.1 题目

在这里插入图片描述

4.2 题解

class Solution {
    
    public List<List<Integer>> permute(int[] nums) {
    
        int len = nums.length;
        List<List<Integer>> res = new ArrayList<>();
        if(len == 0)
            return res;

        // 记录每一次排列中元素进path的信息
        boolean[] used = new boolean[len];
        List<Integer> path = new ArrayList<>();
        dfs(nums, len, 0, path, used, res);
        return res;
    }

    private void dfs(int[] nums, int len, int depth, List<Integer> path, boolean[] used, List<List<Integer>> res){
    
        // 递归终止条件:depth==len,也就是说所有的数已经取完
        if(depth == len){
    
            res.add(new ArrayList<>(path));
            return;
        }

        // 在还未选择的数中依次选择一个元素作为下一个位置的元素
        for(int i = 0; i < len; i++){
    
            // 如果该元素并未进path
            if(!used[i]){
    
                path.add(nums[i]);
                used[i] = true;

                // 继续向下搜索直至path满为止
                dfs(nums, len, depth + 1, path, used, res);
                used[i] = false;
                path.remove(path.size() - 1);
            }
        }

    }
}

注:题解好好看。

5 784. 字母大小写全排列

5.1 题目

在这里插入图片描述

5.2 题解

class Solution {
    
    public List<String> letterCasePermutation(String s) {
    
        List<String> res = new ArrayList<>();
        char[] path = new char[s.length()];
        dfs(0, s.toCharArray(), res);
        return res;
    }

    private void dfs(int index, char[] s, List<String> res){
    
        if(index == s.length){
    
            res.add(new String(s));
            return;
        }

        if(Character.isLetter(s[index])) {
     //用Character.isLetter()判断是否为字母,很方便
            s[index] = Character.toLowerCase(s[index]);
            dfs(index + 1, s, res); //对于字母保证生成小写的和大写的两种情况
            s[index] = Character.toUpperCase(s[index]);
        } //分别用Character.toLowerCase()和Character.toUpperCase()转化大小写字母,再也不用写判断手动转化啦

        dfs(index + 1, s, res); //不管是数字还是字母都要进入下一个字符
    }
}

注:这道题的细节没搞清楚,题解在此。

6 总结

感觉不管是递归还是回溯问题,都有一定的模板,等刷完所有的题型回来复习这些题,猛刷同类型。

原网站

版权声明
本文为[寄生于黑暗中的光]所创,转载请带上原文链接,感谢
https://blog.csdn.net/A2460865183/article/details/125211405