【回溯算法】二、回溯算法模板的关于分析题目是否需要使用used数组和start的详细总结

一、什么时候必须用used数组?

结论:给定数组nums里有重复元素,必须用used数组。

1.如[1,2,2,2,3]有重复元素,需要借助used[i]去重第二个以及之后的重复元素(也就是1,2和3之间的两个2);如力扣例题t40t90,

int used[i] = new used[nums.length];//默认0未用1用,但用完后会归为0;
Arrays.sort(nums);//升序,方便让值一样的元素连续着,
//然后进行去重第二个以及之后的重复元素的判断。

//防止计算重复了以重复元素为首的情况,
//只计算第一个重复元素为首的情况
if(i > 0 && nums[i-1] == nums[i] && used[i-1] == 0)
/*如例子[1,2,2,3],能进到此if语句的,
一定是重复元素里的第二个及以后,
在遍历到后面的2的时候,
发现第一个2曾经进入过path了,
所有以2为首的情况已经计算过了,
所以跳过后面所有以2为首的情况。
*/
	continue;
	
	path.addLast(nums[i]);
	used[i] = 1;//此时nums[i]已经在path里了,
	//所以used[i]为1
	backTracking(nums,used);
	path.removeLast();
	used[i] = 0;//此时nums[i]不在path里了,
	//所以used[i]为0,但此时的0与默认0不一样,
	//因为此时以nums[i]为首的所有情况已经都在path里了

2.如果给定的nums内无重复元素如[1,2,3],那么用不用used都行。

二、允不允许元素使用自己?

结论:如果结果集不允许元素重复使用自己(注意也许题目中元素有重复,允许使用与自己相等的元素,但不是元素自己复用如t40明确要求candidates数组中的每个数字在每个组合中只能使用一次。),那么分两种情况:

规则2.1有start,backTracking(nums,i+1);//用i+1避开重复使用自己
规则2.2无start,即代表每次都从0开始遍历,则
if(used[i] == 1)//因为没有start而是从0遍历,
//所以可以往回走,因此可能会遍历到自己,
//但是结果里要保证没有自己(可以有和自己等值的重复元素)
//可以借助used避免用到自己
	continue;

注解:t40这道题比较特殊,它因为要求结果集内元素递增(即不能往回走)所以出现了start,因此根据规则2.1,要用i+1来避免使用自己;同时它给定的数组又有重复元素,所以必须用used去掉重复元素的影响。

三、什么时候必须用start?

结论:如果结果集不允许有如[1,3,2]这种非递增的结果只允许有[1,3,4],[1,2,3]等递增结果,那么必须用start来防止往回走。

四、总结

1.数组nums有没有重复元素?
有重复元素就得用used,没有就不必;
2.每个结果内的元素必须是递增的吗?
必须递增就要用start防止往回走,不是必须递增就不用start而是每次让i都从0开始遍历。
3.不允许使用同一个元素多次吗?
不允许就要用start配合i+1或者没有start即每次都从0遍历时判断当used[i]==1时continue来避免同一个元素使用多次。

特别注意

在题目剑指 Offer 38. 字符串的排列中,既允许原始数组有重复元素(也就是说必须用used去掉与自己相同的重复元素),而且允许往回走(也就是说必须没有start),那么就无法同时用if(used[i] == 1) continue;if(i > 0 && nums[i-1] == nums[i] && used[i-1] == 0) continue;来分别防止使用自己和防止使用与自己相同的重复元素。
本题题解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值