Day29--数据结构与算法(Java) 回溯问题:递增子序列,全排列,全排列 II

一、491.递增子序列

491. 递增子序列 - 力扣(Leetcode)

给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。

示例:

  • 输入: [4, 6, 7, 7]
  • 输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]

为了有鲜明的对比,我用[4, 7, 6, 7]这个数组来举例,抽象为树形结构如图:

491. 递增子序列1

class Solution {
    List<List<Integer>>result=new ArrayList<>();
    LinkedList<Integer>path=new LinkedList<>();
    public List<List<Integer>> findSubsequences(int[] nums) {
   backTracking(nums,0);
   return result;
    }
    private void backTracking(int[] nums,int startIndex)
    {
     if(path.size()>1)
     {
          result.add(new ArrayList<>(path));
     }
      HashMap<Integer,Integer> map = new HashMap<>();
     for(int i=startIndex;i<nums.length;i++)
     {
        if(!path.isEmpty()&&nums[i]<path.getLast())
        {
            continue;
        }
        if(map.getOrDefault(nums[i],0)>=1)
        {
            continue;
        }
        map.put(nums[i],map.getOrDefault(nums[i],0)+1);
        path.add(nums[i]);
        backTracking(nums,i+1);
        path.removeLast();
     }
    }
}

二、46.全排列

力扣题目链接

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

  • 输入: [1,2,3]
  • 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]

我以[1,2,3]为例,抽象成树形结构如下:

此时可以感受出排列问题的不同:

  • 每层都是从0开始搜索而不是startIndex
  • 需要used数组记录path里都放了哪些元素了
class Solution {
    List<List<Integer>> result=new ArrayList<>();
    LinkedList<Integer>path=new LinkedList<>();
    boolean []used;
    public List<List<Integer>> permute(int[] nums) {
    used=new boolean[nums.length];
    permuteHelper(nums);
    return result;
    }
    private void permuteHelper(int [] nums)
    {
     if(path.size()==nums.length)
     {
         result.add(new ArrayList<>(path));
         return ;
     }
     for(int i=0;i<nums.length;i++)
     {
      if(used[i]==true)
      {
          continue;
      }
      used[i]=true;
      path.add(nums[i]);
      permuteHelper(nums);
      used[i]=false;
      path.removeLast();
     }
    }
}

三、47.全排列 II

力扣题目链接

需要强调的是去重一定要对元素进行排序,这样我们才方便通过相邻的节点来判断是否重复使用了

我以示例中的 [1,1,2]为例 (为了方便举例,已经排序)抽象为一棵树,去重过程如图:

47.全排列II1

图中我们对同一树层,前一位(也就是nums[i-1])如果使用过,那么就进行去重。

一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果

class Solution {
    List<List<Integer>>result=new ArrayList<>();
    LinkedList<Integer> path=new LinkedList<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
     boolean [] used=new boolean[nums.length];
     Arrays.fill(used,false);
     Arrays.sort(nums);
     backTracking(nums,used);
     return result;
    }
    private void backTracking(int[] nums,boolean []used)
    {
     if(path.size()>=nums.length)
     {
         result.add(new ArrayList<>(path));
         return;
     }
     for(int i=0;i<nums.length;i++)
     {
         if(i>0&&nums[i]==nums[i-1]&&used[i-1]==false)
         {
             continue;
         }
     if(used[i]==true) continue;
         if(used[i]==false)
         {
             used[i]=true;
             path.add(nums[i]);
             backTracking(nums,used);
             used[i]=false;
             path.removeLast();
         }
     }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值