leetcode17. 电话号码的字母组合,回溯法,穷举法

1.方法:回溯是一种通过穷举所有可能情况来找到所有解的算法。如果一个候选解最后被发现并不是可行解,回溯算法会舍弃它,并在前面的一些步骤做出一些修改,并重新尝试找到可行解。

给出如下回溯函数 backtrack(combination, next_digits) ,它将一个目前已经产生的组合 combination 和接下来准备要输入的数字 next_digits 作为参数。

如果没有更多的数字需要被输入,那意味着当前的组合已经产生好了。
如果还有数字需要被输入:
遍历下一个数字所对应的所有映射的字母。
将当前的字母添加到组合最后,也就是 combination = combination + letter 。
重复这个过程,输入剩下的数字: backtrack(combination + letter, next_digits[1:]) 。

2.代码

class Solution {
	//一个映射表,第二个位置是"abc“,第三个位置是"def"。。。
	//这里也可以用map,用数组可以更节省点内存
	String[] letter_map = {" ","*","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
	public List<String> letterCombinations(String digits) {
		//注意边界条件
		if(digits==null || digits.length()==0) {
			return new ArrayList<>();
		}
		iterStr(digits, "", 0);
		return res;
	}
	//最终输出结果的list
	List<String> res = new ArrayList<>();
	
	//递归函数
	void iterStr(String str, String letter, int index) {
		//递归的终止条件,注意这里的终止条件看上去跟动态演示图有些不同,主要是做了点优化
		//动态图中是每次截取字符串的一部分,"234",变成"23",再变成"3",最后变成"",这样性能不佳
		//而用index记录每次遍历到字符串的位置,这样性能更好
		if(index == str.length()) {
			res.add(letter);
			return;
		}
		//获取index位置的字符,假设输入的字符是"234"
		//第一次递归时index为0所以c=2,第二次index为1所以c=3,第三次c=4
		//subString每次都会生成新的字符串,而index则是取当前的一个字符,所以效率更高一点
		char c = str.charAt(index);
		//map_string的下表是从0开始一直到9, c-'0'就可以取到相对的数组下标位置
		//比如c=2时候,2-'0',获取下标为2,letter_map[2]就是"abc"
		int pos = c - '0';
		String map_string = letter_map[pos];
		//遍历字符串,比如第一次得到的是2,页就是遍历"abc"
		for(int i=0;i<map_string.length();i++) {
			//调用下一层递归,用文字很难描述,请配合动态图理解
			iterStr(str, letter+map_string.charAt(i), index+1);
		}
	}
}

3.分析,这里是用数组保存所有映射,当然也可以使用map映射,如果使用map的话,最后应该根据map.get(key).length()判断

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述: 给定一个只包含正整数的非空数组,是否可以将这个数组分成两个子集,使得两个子集的元素和相等。 示例: 输入:[1, 5, 11, 5] 输出:true 解释:数组可以分割成 [1, 5, 5] 和 [11]。 解题思路: 这是一道经典的 0-1 背包问题,可以使用动态规划或者回溯解决。 使用回溯,需要定义一个 backtrack 函数,该函数有三个参数: - 数组 nums; - 当前处理到的数组下标 index; - 当前已经选择的元素和 leftSum。 回溯过程中,如果 leftSum 等于数组元素和的一半,那么就可以直接返回 true。如果 leftSum 大于数组元素和的一半,那么就可以直接返回 false。如果 index 到达数组末尾,那么就可以直接返回 false。 否则,就对于当前元素,有选择和不选择两种情况。如果选择当前元素,那么 leftSum 就加上当前元素的值,index 就加 1。如果不选择当前元素,那么 leftSum 不变,index 也加 1。最终返回所有可能性的结果中是否有 true。 Java 代码实现: class Solution { public boolean canPartition(int[] nums) { int sum = 0; for (int num : nums) { sum += num; } if (sum % 2 != 0) { return false; } Arrays.sort(nums); return backtrack(nums, nums.length - 1, sum / 2); } private boolean backtrack(int[] nums, int index, int leftSum) { if (leftSum == 0) { return true; } if (leftSum < 0 || index < 0 || leftSum < nums[index]) { return false; } return backtrack(nums, index - 1, leftSum - nums[index]) || backtrack(nums, index - 1, leftSum); } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值