深度优先遍历

来源:互联网 发布:黑魂3改捏脸数据修改 编辑:程序博客网 时间:2024/05/19 19:57

  深度优先遍历是对先序遍历的推广。从某个元素v开始处理,然后递归遍历所有与v相邻的元素。
  

LeetCode 491 Increasing Subsequences

Given an integer array, your task is to find all the different possible increasing subsequences of the given array, and the length of an increasing subsequence should be at least 2 .

Example:
Input: [4, 6, 7, 7]
Output: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]
Note:
The length of the given array will not exceed 15.
The range of integer in the given array is [-100,100].
The given array may contain duplicates, and two equal integers should also be considered as a special case of increasing sequence.

  基本思路:
  1. 以一个元素为首节点,找出跟他相关的所有子序列;
  2. 不再考虑数组里该元素,当作已经删除。换另一个元素作为首节点,找出跟他相关的所有子序列;
  3. 重复上述步骤,直到数组里所有元素都做过一次首节点(由于子序列至少要两个元素,故最后一个最大的元素不考虑)。
  因此,可以使用深度优先遍历。

public class Solution {    public List<List<Integer>> findSubsequences(int[] nums) {        int l = nums.length;        List<List<Integer>> lists = new LinkedList<>();        if(l <= 0)            return lists;        helper(new LinkedList<Integer>(), nums, 0, lists);        return lists;    }    private void helper(LinkedList<Integer> sublist, int[] nums, int start, List<List<Integer>> lists){        if(sublist.size() > 1) //题目要求,子序列至少两个元素            lists.add(new LinkedList<Integer>(sublist));        Set<Integer> used = new HashSet<>();        for(int i = start; i<nums.length; i++){            if(used.contains(nums[i]))                continue;            if(sublist.size() == 0 || nums[i] >= sublist.peekLast()){                used.add(nums[i]);                sublist.add(nums[i]);                helper(sublist, nums, i+1, lists);                sublist.remove(sublist.size()-1);//关键:由于sublist是重复使用的,所以每次用完,需要删除最后一个元素(*其实就是刚刚添加的元素,即该首节点被标记为不再考虑*,因为每次调用helper在sublist.add()后都会有remove,从最后一次倒推即可知道),这样再add给lists时才不会用重复。                                               }        }    }}

  有一类深度优先遍历的题目和动态规划有点类似。类背包问题。

LeetCode 473. Matchsticks to Square

Remember the story of Little Match Girl? By now, you know exactly what matchsticks the little match girl has, please find out a way you can make one square by using up all those matchsticks. You should not break any stick, but you can link them up, and each matchstick must be used exactly one time.

Your input will be several matchsticks the girl has, represented with their stick length. Your output will either be true or false, to represent whether you could make one square using all the matchsticks the little match girl has.

Example 1:
Input: [1,1,2,2,2]
Output: true
Explanation: You can form a square with length 2, one side of the square came two sticks with length 1.

Example 2:
Input: [3,3,3,3,4]
Output: false
Explanation: You cannot find a way to form a square with all the matchsticks.

Note:
The length sum of the given matchsticks is in the range of 0 to 10^9.
The length of the given matchstick array will not exceed 15.

  问题转换描述:给定一个序列,用该序列中的值装填四个背包。每个背包容量为序列和的四分之一。问是否存在一种方法可以装填。
  基本方法:
  1. 依次遍历序列,将元素值放入第一个背包,如果剩下序列的值与背包能否达到目标,则返回true;
  2. 如果剩下序列的值与背包不能达到目标,则将该元素值从第一个背包拿出,放入第二个背包;再看剩下序列的值与背包能否达到目标;
  3. 重复上述步骤,直到可以返回true;否则,如果放在哪一个背包都不可以,则返回false。

public class Solution {    public boolean makesquare(int[] nums) {        if (nums == null || nums.length < 4) return false;        int sum = 0;        for (int num : nums) sum += num;        if (sum % 4 != 0) return false;        //排序预处理有助于加快速度        Arrays.sort(nums);        reverse(nums);        return dfs(nums, new int[4], 0, sum / 4);    }    private boolean dfs(int[] nums, int[] sums, int index, int target) {        if (index == nums.length) {//边界条件            if (sums[0] == target && sums[1] == target && sums[2] == target) {            return true;            }            return false;        }        //基本处理流程        for (int i = 0; i < 4; i++) {            if (sums[i] + nums[index] > target) continue;//这也算是一个边界条件。如果该元素nums[index]放入此包sums[i]中溢出了,则必然false,直接看下一个背包。            sums[i] += nums[index];            if (dfs(nums, sums, index + 1, target)) return true;            sums[i] -= nums[index];//一定记得拿出来,和上一例中的sublist.remove()是类似的道理,在此类深度优先遍历中要注意        }        return false;    }    private void reverse(int[] nums) {        int i = 0, j = nums.length - 1;        while (i < j) {            int temp = nums[i];            nums[i] = nums[j];            nums[j] = temp;            i++; j--;        }    }}
原创粉丝点击