46 Permutations

 输入一个不重复的数组 ,写出这个数组的排列,不能重复。
 例如 输入nums=[1,2,3],输出
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

 思路:可以看到 第0位(从左开始数)有nums.length个数字可以选择:1,2,3,在第0位确定以后,第1位有nums.length-1个数字可以选择,例如p[0] = 1,p[1]只可能为2 或者3。所以重要的是记录哪些下标的元素已经被选择过。

public class Solution {private boolean[] p;//记录选中过的下标private List<List<Integer>> list;public List<List<Integer>> permute(int[] nums) {int[] newarray=new int[nums.length];//存放选中的数字p = new boolean[nums.length];list = new ArrayList<List<Integer>>();robot(0,newarray,nums);return list;}public void robot(int idx,int[] newarray,int[] nums){if(idx>=nums.length){List<Integer> l = new ArrayList<Integer>();for(int i=0;i<newarray.length;i++){l.add(newarray[i]);}list.add(l);return;}for(int i=0;i<nums.length;i++){if(p[i]==false){newarray[idx]=nums[i];p[i]=true;robot(idx+1,newarray,nums);p[i]=false;}}}
}

47 Permutations II

 输入一个重复的数组 ,写出这个数组的排列,不能重复。
 例如输入 [1,1,2] 输出
[
[1,1,2],
[1,2,1],
[2,1,1]
]
 思路:这与46的区别是输入的数组中有重复的数字。如果按照46的思路做,会出现重复的结果。我们先按照46的来做一下吧。用”数字(下标)”这种方式表示数组元素:1(0) 1(1) 2(2)。这样才能把相同的数字区分开来。为了方便,我们先将输入的数组排序。按照46的思路得到以下组合:
1(0) 1(1) 2(2)
1(0) 2(2) 1(1)
1(1) 1(0) 2(2)
1(1) 2(2) 1(0)
2(2) 1(0) 1(1)
2(2) 1(1) 1(0)
 重点标记的是重复的元素。分析一下。第0位可以选择的元素有 nums[0], nums[1], nums[2],但是当已经选择nums[0]之后,再遇到nums[1]=nums[0]的时候nums[1]是不能选择的,否则就重复了。所以第0位可以选择的元素有 nums[0], nums[2]。每一位都是,判断nums[idx]能不能选择标准是nums[idx-1]=nums[idx]是否为true。
这个判断怎么加呢?下面记录一下我自己犯过的错。

处理情况1

for(int i=0;i<nums.length;i++){if(p[i]==false){newarray[idx]=nums[i];p[i]=true;robot(idx+1,newarray,nums);p[i]=false;for (int j = i + 1; j < nums.length; j++){if (nums[j] != nums[j - 1]) {i = j - 1;break;}}}}  

 每到一个位置,先选择一个元素,再处理下一个元素和前面的元素是否相同。这里判断的时候没有考虑前面的元素是否会选中,可能会有多余的操作。更重要的是没有处理如果重复元素是最后一个元素怎么处理。失败用例:[1,1]。
 

    for(int i=0;i<nums.length;i++){if(p[i]==false){newarray[idx]=nums[i];p[i]=true;robot(idx+1,newarray,nums);p[i]=false;int j = i + 1;for (; j < nums.length; j++){if (nums[j] != nums[j - 1]) {i = j - 1;break;}}if(j==nums.length){break;}}}

 改成这样就对了。但是这样代码不够优雅。

处理情况2

    for(int i=0;i<nums.length;i++){if(p[i]==false && (i==0 || (nums[i]!=newarray[idx]))){newarray[idx]=nums[i];p[i]=true;robot(idx+1,newarray,nums);p[i]=false;}}  

 因为newarray[idx]记录了上一次选择的值,所以想到只要判断这次的候选值nums[i]和newarray[idx]不同就好了。这次的错误是因为i==0的判断是有误的。因为不一定每次都是nums[0]是第一个被选中的。例如当第0位选择nums[0],在选第2位的时候第一个被选中的一定是nums[1] ,所以这里应该用一个boolean变量表示本次是不是对idx已经选过一个值了。
 

        boolean selected = false;for(int i=0;i<nums.length;i++){if(p[i]==false && (!selected || (nums[i]!=newarray[idx]))){selected = true;newarray[idx]=nums[i];p[i]=true;robot(idx+1,newarray,nums);p[i]=false;}}  

处理情况3

 接着我还用了一种方式处理。使用了一个单独的变量记录在选择idx的候选值时候,上一个选择的值。

 int preNum = -1;boolean selected = false;for(int i=0;i<nums.length;i++){if(p[i]==false && (selected==false || (nums[i]!=preNum))){selected = true;preNum = nums[i];newarray[idx]=nums[i];p[i]=true;robot(idx+1,newarray,nums);p[i]=false;}}   

 总结:大概可以在编程的时候行不通。一定是一定可以才可以。在backtracing中最重要的是理解每一步的状态。

leetcode之回溯backtracing专题2相关推荐

  1. leetcode之回溯backtracing专题5

    参考链接 http://blog.csdn.net/zhongkeli/article/details/6966805 https://leetcode.com/problems/permutatio ...

  2. leetcode之回溯backtracing专题4

    131 Palindrome Partitioning 输入一个字符串s,将s分割为n个子串,每个子串都是一个回文.返回s有多少种分割方式. 例如输入:"aab" 输出:[ [&q ...

  3. leetcode之回溯backtracing专题3

    17 Letter Combinations of a Phone Number 手机上每个数字按钮旁边都有3-4个字母,输入数字字符串,输出可能的字母组合. 例如输入:"23" ...

  4. leetcode之回溯backtracing专题1

    39 Combination Sum 给一组整数,给一个目标整数.从数组中任意选择几个数,这几个数的和等于目标整数.数组中每个数字可以选择多次. 例如given candidate set [2, 3 ...

  5. LeetCode Hot100 ---- 回溯算法专题

    回溯算法是什么?解决回溯算法相关的问题有什么技巧?如何学习回溯算法?回溯算法代码是否有规律可循? 其实回溯算法其实就是我们常说的 DFS 算法,本质上就是一种暴力穷举算法. 解决一个回溯问题,实际上就 ...

  6. Leetcode总结(Island专题)

    Leetcode总结之 Island专题 Table of Contents 总结 200. Number of Islands 305. Number of Islands II 695. Max ...

  7. leetcode的回溯算法题目用这个模板解题,一网打尽,so easy!!!

    " 这是本人第 46 篇原创博文,每周至少两篇更新,谢谢赏脸阅读文章 这一篇文章来讲解一下如何做leetcode回溯算法题目,这一段时间我把leetcode上面的回溯算法的题目都刷了个遍,发 ...

  8. 【LeetCode】回溯 N皇后(DFS、子集、组合问题)

    总结 技巧: 子集和组合问题经常需要一个start来标记开始选择的起始位置来达到去重的目的,排列问题不用 [46.全排列] 排列问题常需要一个used数组来标记已经选择的元素(也可以同时用于去重) C ...

  9. leetcode two sum python_LeetCode专题-Python实现之第1题:Two Sum

    相关代码已经上传到github:https://github.com/exploitht/leetcode-python 文中代码为了不动官网提供的初始几行代码内容,有一些不规范的地方,比如函数名大小 ...

最新文章

  1. Wireshark数据抓包分析(网络协议篇)第1章网络协议抓包概述
  2. 蚂蚁疾奔:蚂蚁集团两地上市全速推进
  3. 算法讲解 -- 二分图之 匈牙利算法
  4. xCode 安装Mobile Device Framework出错的问题的解决方法
  5. mysql中having的例子_有关mysql中having子句对组记录进行筛选的例子
  6. Java Web提交任务到Spark Spark通过Java Web提交任务
  7. tornado之获取参数
  8. Matlab线型、标记、颜色表示代码
  9. eeupdate 更新MAC地址
  10. 论外挂入门(辅助入门)图色辅助与内存辅助的优与弊
  11. 围棋棋盘 -《跟小海龟学Python》案例代码
  12. 最新可用的快速FLV转MP4方法,解决转换后无声音及视频不流畅问题
  13. python优雅编程之旅
  14. kubernetes部署失败的原因
  15. pyqt5 等待界面 (QMovie 加载 gif)
  16. JS在VS coder界面写promt和alter语句无法在浏览器页面显示
  17. 有用的“歪门邪道”-设计模式
  18. web安全基础知识-part2
  19. 谷歌扩展插件官方下载地址
  20. 想做游戏测试工程师?这几点不知道可不行!

热门文章

  1. 部署OpenStack问题汇总(五)--openstack中删除虚拟主机,状态一直未deleting
  2. PHP扩展开发(3)-config.m4
  3. websocket + node.js聊天系统
  4. linux-tar命令详解
  5. 微软应提前发布专用于ARM处理器的Windows 8平板电脑系统
  6. SharePoint中的权限体系
  7. Linux循环登录怎么解决,文本模式循环登录! 求解决
  8. skywalking 源码解析——多线程变量传递 EnhancedInstance
  9. elasticsearch 6.x (一) 部署 windows入门 spingboot连接
  10. android任务 进程 线程详解,Android任务、进程、线程详解