LeetCode——バックトラッキング (1)

質問に答えるための順序とアイデアは、Code Caprice、Web サイトのアドレス: https://programmercarl.comから得られます。

目次

77. コンビネーション

216. 組み合わせ和Ⅲ

17. 電話番号のアルファベット

39. 組み合わせ和

40. 組み合わせ和Ⅱ

77. コンビネーション

2 つの整数の合計を指定すると n 、  範囲内の数値の 可能なすべての 組み合わせkを返します 。[1, n]k

回答は任意の順序で返すことができます  。

输入:n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * @author light
 * @Description 组合
 *
 * 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
 *
 * 你可以按 任何顺序 返回答案。
 * @create 2023-08-27 10:50
 */
public class CombineTest {
	public static void main(String[] args) {
		Scanner input=new Scanner(System.in);
		int n= input.nextInt();
		int k= input.nextInt();
		System.out.println(combine(n, k));
	}
	public  static List<List<Integer>> res=new ArrayList<>(); //存放结果集
	public  static List<Integer> path=new ArrayList<>();  //存放路径变量
	public static List<List<Integer>> combine(int n, int k) {
		backtracking(n,k,1);

		return res;
	}

	//startIndex:记录每层递归数组起始位置---防止数组元素重复---组合
	private static void backtracking(int n, int k, int startIndex) {
		if(path.size()==k){
			res.add(new ArrayList<>(path));
			return;
		}
		//剪枝操作:可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。
		//如果for循环选择的起始位置之后的元素个数已经不足我们需要的元素个数了,那么就没有必要搜索了。
		/*
		接下来看一下优化过程如下:
		已经选择的元素个数:path.size();
		还需要的元素个数为: k - path.size();
		在集合n中至多要从该起始位置 : n - (k - path.size()) + 1,开始遍历
		为什么有个+1呢,因为包括起始位置,我们要是一个左闭的集合。
		 */
		for (int i = startIndex; i <= n-(k- path.size())+1; i++) {
			path.add(i);
			backtracking(n,k,i+1);
			//回溯
			path.remove(path.size()-1);
		}
	}
}

216. 組み合わせ和Ⅲ

合計すると次の条件を満たす数値n に なるすべての組み合わせを見つけます 。k 

  • 1 ~ 9 の数字のみを使用してください
  • 各番号は 最大 1 回使用してください 

考えられるすべての有効な組み合わせのリストを返します  。リストに同じ組み合わせを 2 回含めることはできず、組み合わせは任意の順序で返すことができます。

输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * @author light
 * @Description 组合总和III
 *
 * @create 2023-08-27 11:18
 */
public class CombinationSum3Test {
	public static void main(String[] args) {
		Scanner input=new Scanner(System.in);
		int n= input.nextInt();
		int k= input.nextInt();
		System.out.println(combinationSum3(k, n));
	}
	public static List<List<Integer>> res=new ArrayList<>();
	public static List<Integer> path=new ArrayList<>();
	public static List<List<Integer>> combinationSum3(int k, int n) {
		backtracking(k,n,1,0);
		return res;
	}

	private static void backtracking(int k, int n, int startNum,int sum) {
		if(sum>n){
			return;
		}
		if(path.size()==k){
			if(sum==n){
				res.add(new ArrayList<>(path));
			}
			return;
		}

		for (int i = startNum; i <=9-(k- path.size())+1 ; i++) {
			path.add(i);
			sum+=i;
			backtracking(k,n,i+1,sum);
			//回溯
			path.remove(path.size()-1);
			sum-=i;
		}
	}
}

17. 電話番号のアルファベット

数値のみを含む文字列を指定すると 2-9 、それが表すことができるすべての文字の組み合わせを返します。回答は任意の順序で返すことができます  。

数字と文字のマッピングを以下に示します (電話のキーと同じ)。1 はどの文字にも対応しないことに注意してください。

输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

 

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * @author light
 * @Description 电话号码的字母组合
 * @create 2023-08-27 12:15
 */
public class LetterCombinationsTest {
	public static void main(String[] args) {
		Scanner input=new Scanner(System.in);
		String digits=input.next();
		System.out.println(letterCombinations(digits));
	}
	public static List<String> list=new ArrayList<>();
	public static List<String> letterCombinations(String digits) {
		if(digits==null||digits.length()==0){
			return list;
		}
		//初始对应所有的数字,为了直接对应2-9,新增了两个无效的字符串""
		String[] numString = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};

		backtracking(digits,numString,0);
		return list;
	}
	public static StringBuilder sb=new StringBuilder();

	private static void backtracking(String digits, String[] numString, int num) {
		if(num==digits.length()){
			list.add(sb.toString());
			return;
		}
		String string=numString[digits.charAt(num)-'0'];
		for (int i = 0; i <string.length() ; i++) {
			sb.append(string.charAt(i));
			backtracking(digits,numString,num+1);
			sb.deleteCharAt(sb.length()-1);
		}
	}
}

39. 組み合わせ和

繰り返し要素のない 整数の配列 candidates とターゲット integer を 指定すると target 、 candidates 合計がターゲット number になる数値 のさまざまな組み合わせをtarget すべて見つけ 、それをリストとして返します。これらの組み合わせは任意の順序で返すことができます  。 

candidates 内の 同じ 番号は 無制限に繰り返し選択できます 。少なくとも 1 つの数字が異なるように選択された場合、2 つの組み合わせは異なります。 

特定の入力について、 target 合計の異なる組み合わせの数が 未満である ことが保証されます150 。

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * @author light
 * @Description 组合总和
 *
 * @create 2023-08-27 15:58
 */
public class CombinationSumTest {
	public static void main(String[] args) {
		Scanner input=new Scanner(System.in);
		int n=input.nextInt();
		int[] candidates=new int[n];
		for (int i = 0; i < n; i++) {
			candidates[i]=input.nextInt();
		}
		int target= input.nextInt();
		System.out.println(combinationSum(candidates, target));

	}

	public static List<List<Integer>> res=new ArrayList<>();
	public static List<Integer> path=new ArrayList<>();
	public static List<List<Integer>> combinationSum(int[] candidates, int target) {
		backtracking(candidates,target,0,0);
		return res;
	}

	private static void backtracking(int[] candidates, int target, int sum, int startIndex) {
		if(sum==target){
			res.add(new ArrayList<>(path));
			return;
		}
		if(sum>target){
			return;
		}
		for (int i = startIndex; i < candidates.length; i++) {
			path.add(candidates[i]);
			sum+=candidates[i];
			backtracking(candidates,target,sum,i);
			path.remove(path.size()-1);
			sum-=candidates[i];
		}
	}
}

40. 組み合わせ和Ⅱ

一連の候補数値 candidates とターゲット数値 が与えられた場合target 、 candidates 数値の合計が になる すべてのtarget 組み合わせを見つけます。

candidates の各番号は、各組み合わせで 1 回だけ使用できます 。

注:ソリューション セットには、繰り返しの組み合わせを含めることはできません。 

输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

/**
 * @author light
 * @Description 组合总和II
 * @create 2023-08-27 16:11
 */
public class CombinationSum2Test {
	public static void main(String[] args) {
		Scanner input=new Scanner(System.in);
		int n=input.nextInt();
		int[] candidates=new int[n];
		for (int i = 0; i < n; i++) {
			candidates[i]=input.nextInt();
		}
		int target= input.nextInt();
		System.out.println(combinationSum2(candidates, target));
	}
	public static List<List<Integer>> res=new ArrayList<>();
	public static List<Integer> path=new ArrayList<>();

	public static List<List<Integer>> combinationSum2(int[] candidates, int target) {
		Arrays.sort(candidates);
		int[] used=new int[candidates.length]; //判断集合重元素是否重复使用
		Arrays.fill(used,0);
		backtracking(candidates,target,0,used);
		return res;
	}

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

		for (int i = startIndex; i < candidates.length&&target-candidates[i]>=0; i++) {
			//要进行树层去重(横向
			if(i>0&&candidates[i]==candidates[i-1]&&used[i-1]==0){
				continue;
			}
			path.add(candidates[i]);
			target-=candidates[i];
			used[i]=1;
			backtracking(candidates,target,i+1,used);
			path.remove(path.size()-1);
			target+=candidates[i];
			used[i]=0;
		}
	}
}

おすすめ

転載: blog.csdn.net/zssxcj/article/details/132521212