代码随想录算法训练营第20天|39. 组合总和、40. 组合总和 II、131. 分割回文串

39. 组合总和

回溯三部曲
    1.确定回溯函数返回值和参数
        返回值为void,参数为给定数组candidates,目标值target,和当前开始遍历的数组下标?
    2.确定回溯终止条件
        当前和大于目标值,直接中止此次回溯。或当相加的数字之和等于目标值target,将目标集合加入结果集,中止此次回溯。
    3.确定回溯单层过程
        从当前开始遍历的数组下标开始遍历剩余的数组元素,将遍历到的元素加到和上,进入下一个递归层。递归出来之后进行回溯,减去当前遍历到的元素值

    能否有剪枝操作?
      可以,先将candidates数组排序后,将sum大于目标值中止递归放在for循环中,就少进递归层的次数。

class Solution {

	List<List<Integer>> res = new ArrayList<>();
	List<Integer> item = new ArrayList<>();
	int sum = 0;

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
		Arrays.sort(candidates);
		backtracking(candidates, target, 0);
		return res;
    }

	private void backtracking(int[] candidates, int target, int startIndex){
		if(sum == target){
			res.add(new ArrayList<>(item));
			return;
		}

		for(int i = startIndex; i < candidates.length; i++){
			if(sum + candidates[i] > target){
				break;
			}
			item.add(candidates[i]);
			sum += candidates[i];
			backtracking(candidates, target, i);
			item.remove(item.size() - 1);
			sum -= candidates[i];
		}
	}

}

——————————————————————————————————————————

40. 组合总和 II 


  本题有重复的元素,需要去重
  去重之前要先对candidates数组进行排序
  回溯三部曲
    1.确定回溯函数返回值和参数
        返回值为void,参数为给定数组candidates,目标值target,和当前开始遍历的数组下标
    2.确定回溯终止条件
        当前和大于目标值,直接中止此次回溯。或当相加的数字之和等于目标值target,将目标集合加入结果集,中止此次回溯。
    3.确定回溯单层过程
        从当前开始遍历的数组下标开始遍历剩余的数组元素,将遍历到的元素加到和上,进入下一个递归层。递归出来之后进行回溯,减去当前遍历到的元素值

    能否有剪枝操作?
      可以,先将candidates数组排序后,将sum大于目标值中止递归放在for循环中,就少进递归层的次数。

 

class Solution {

	List<List<Integer>> res = new ArrayList<>();
	List<Integer> item = new ArrayList<>();
	int sum = 0;

	public List<List<Integer>> combinationSum2(int[] candidates, int target) {
		Arrays.sort(candidates);
		backtracking(candidates, target, 0);
		return res;
    }

	private void backtracking(int[] candidates, int target, int startIndex){
		if(sum == target){
			res.add(new ArrayList<>(item));
			return;
		}

		for(int i = startIndex; i < candidates.length; i++){
			//去重
			if(i > startIndex && candidates[i] == candidates[i - 1]){
				continue;
			}
			if(sum + candidates[i] > target){
				break;
			}
			item.add(candidates[i]);
			sum += candidates[i];
			backtracking(candidates, target, i + 1);
			item.remove(item.size() - 1);
			sum -= candidates[i];
		}
	}
}

 ——————————————————————————————————————————

131. 分割回文串

 可以使用动态规划来判断子串是否是回文子串
    具体做法:二维dp数组isPalindrome[i][j]表示从i到j的子串是否是回文子串
    当[i+1,j-1]是回文子串时,如果s[i]和s[j]相等,[i,j]是回文子串,否则不是
    当[i+1,j-1]不是回文子串时,[i,j]不是回文子串
    dp数组的遍历顺序:因为要从[i+1,j-1]到[i,j],所以遍历顺序i从大到小,j从小到大

    本题有重复的元素,需要去重
    去重之前要先对candidates数组进行排序
    回溯三部曲
    1.确定回溯函数返回值和参数
        返回值为void,参数为给定原字符串s,和当前开始遍历的字符串字符下标
    2.确定回溯终止条件
        当遍历开始下标超出字符串长度时,中止递归
    3.确定回溯单层过程
        从当前层开始位置开始向后遍历,判断[start,end]的子串是否是回文子串,是的话,加入过程集合,进入下一层递归层。
      记得回溯

class Solution {
	List<List<String>> res = new ArrayList<>();
	List<String> item = new ArrayList<>();

	boolean[][] isPalindrome;
	public List<List<String>> partition(String s) {
		isPalindrome = new boolean[s.length()][s.length()];
		for(int i = 0; i < s.length(); i++){
			Arrays.fill(isPalindrome[i], false);
		}
		isPalindrome(s);
		backtracking(s, 0);
		return res;
    }

	private void backtracking(String s, int startIndex){
		if(startIndex >= s.length()){
			res.add(new ArrayList<>(item));
			return;
		}

		for(int i = startIndex; i < s.length(); i++){
			//if(!isPalindrome(s, startIndex, i)){
			if(!isPalindrome[startIndex][i]){
				continue;
			}
			item.add(s.substring(startIndex, i + 1));
			backtracking(s, i + 1);
			item.remove(item.size() - 1);
		}
	}
    //基础的回文子串判断方法
	private boolean isPalindrome(String s, int statIndex, int endIndex){
		while(endIndex > statIndex){
			if(s.charAt(endIndex) != s.charAt(statIndex)){
				return false;
			}
			endIndex--;
			statIndex++;
		}
		return true;
	}
    //通过动态规划判断回文子串
	private void isPalindrome(String s){
		for(int i = s.length() - 1; i >= 0; i--){
			for(int j = 0; j < s.length(); j++){
				if(i == j) isPalindrome[i][j] = true;
				if(i + 1 == j) isPalindrome[i][j] = s.charAt(i) == s.charAt(j);
				else if (i < j) {
					isPalindrome[i][j] = isPalindrome[i + 1][j - 1] && (s.charAt(i) == s.charAt(j));
				}
			}
		}

	}
}

 

  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二天的算法训练主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,使得子数组的和大于等于给定的目标值。这里可以使用滑动窗口的方法来解决问题。使用两个指针来表示滑动窗口的左边界和右边界,通过移动指针来调整滑动窗口的大小,使得滑动窗口中的元素的和满足题目要求。具体实现的代码如下: ```python def minSubArrayLen(self, target: int, nums: List[int]) -> int: left = 0 right = 0 ans = float('inf') total = 0 while right < len(nums): total += nums[right] while total >= target: ans = min(ans, right - left + 1) total -= nums[left] left += 1 right += 1 return ans if ans != float('inf') else 0 ``` 以上就是第二十二天的算法训练的内容。通过这些题目的练习,可以提升对双指针和滑动窗口等算法的理解和应用能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值