搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
示例 1: 输入: nums = [1,3,5,6], target = 5 输出: 2
示例 2: 输入: nums = [1,3,5,6], target = 2 输出: 1
示例 3: 输入: nums = [1,3,5,6], target = 7 输出: 4
解题思路:二分搜索
public int searchInsert(int[] nums, int target) {int len = nums.length;// 因为数组是升序的,判断最后一个元素与要插入的元素大小if (nums[len - 1] < target) {return len;}int left = 0;int right = len - 1;// 在区间 nums[left..right] 里查找第 1 个大于等于 target 的元素的下标while (left < right) {// 从中间开始分int mid = (left + right) / 2;if (nums[mid] < target){// 下一轮搜索的区间是 [mid + 1..right]left = mid + 1;} else {// 下一轮搜索的区间是 [left..mid]right = mid;}}return left;}
有效数独
请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
public boolean isValidSudoku(char[][] board) {Map<Integer, Set<Integer>> row = new HashMap<>();Map<Integer, Set<Integer>> col = new HashMap<>();Map<Integer, Set<Integer>> area = new HashMap<>();for(int i = 0; i < 9; i++) {row.put(i, new HashSet<>());col.put(i, new HashSet<>());area.put(i, new HashSet<>());}for(int i = 0; i < 9; i++) {for(int j = 0; j < 9; j++) {char c = board[i][j];if (c == '.') {continue;}int u = c - '0';int idx = i / 3 * 3 + j / 3;if(row.get(i).contains(u) || col.get(j).contains(u) || area.get(idx).contains(u)) {return false;}row.get(i).add(u);col.get(j).add(u);area.get(idx).add(u);}}return true;}
解数独
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
解题思路:回溯算法。
private boolean[][] line = new boolean[9][9];private boolean[][] column = new boolean[9][9];private boolean[][][] block = new boolean[3][3][9];private boolean valid = false;private List<int[]> spaces = new ArrayList<int[]>();public void solveSudoku(char[][] board) {for(int i = 0; i < 9; ++i) {for(int j = 0; j < 9; ++j) {if(board[i][j] == '.') {spaces.add(new int[]{i, j});} else {int digit = board[i][j] - '0' - 1;line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true;}}}dfs(board, 0);}public void dfs(char[][] board, int pos) {if (pos == spaces.size()) {valid = true;return;}int [] space = spaces.get(pos);int i = space[0];int j = space[1];for(int digit = 0; digit < 9 && !valid; ++digit) {if(!line[i][digit] && !column[j][digit] && !block[i / 3][j / 3][digit]) {line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true;board[i][j] = (char) (digit + '0' + 1);dfs(board, pos + 1);line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = false;}}}
组合总和
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
示例 1:
输入:candidates = [2,3,6,7], target = 7 输出:[[2,2,3],[7]] 解释: 2 和 3
可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。 7 也是一个候选, 7 = 7 。 仅有这两种组合。
示例 2:
输入: candidates = [2,3,5], target = 8 输出: [[2,2,2,2],[2,3,3],[3,5]]
示例3:
输入: candidates = [2], target = 1 输出: []
public List<List<Integer>> combinationSum(int[] candidates, int target) {int len = candidates.length;List<List<Integer>> res = new ArrayList<>();if (len == 0) {return res;}Deque<Integer> path = new ArrayDeque<>();dfs(candidates, 0, len, target, path, res);return res;}/*** @param candidates 候选数组* @param begin 搜索起点* @param len 冗余变量,是 candidates 里的属性,可以不传* @param target 每减去一个元素,目标值变小* @param path 从根结点到叶子结点的路径,是一个栈* @param res 结果集列表*/private void dfs(int[] candidates, int begin, int len, int target, Deque<Integer> path, List<List<Integer>> res) {// target 为负数和 0 的时候不再产生新的孩子结点if (target < 0) {return;}if (target == 0) {res.add(new ArrayList<>(path));return;}// 重点理解这里从 begin 开始搜索的语意for (int i = begin; i < len; i++) {path.addLast(candidates[i]);// 注意:由于每一个元素可以重复使用,下一轮搜索的起点依然是 i,这里非常容易弄错dfs(candidates, i, len, target - candidates[i], path, res);// 状态重置path.removeLast();}}
组合总和2
给定一个候选人编号的集合 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] ]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5, 输出: [ [1,2,2], [5] ]
List<int[]> freq = new ArrayList<int[]>();List<List<Integer>> ans = new ArrayList<List<Integer>>();List<Integer> sequence = new ArrayList<Integer>();public List<List<Integer>> combinationSum2(int[] candidates, int target) {Arrays.sort(candidates);for (int num : candidates) {int size = freq.size();if (freq.isEmpty() || num != freq.get(size - 1)[0]) {freq.add(new int[]{num, 1});} else {++freq.get(size - 1)[1];}}dfs(0, target);return ans;}public void dfs(int pos, int rest) {if (rest == 0) {ans.add(new ArrayList<Integer>(sequence));return;}if (pos == freq.size() || rest < freq.get(pos)[0]) {return;}dfs(pos + 1, rest);int most = Math.min(rest / freq.get(pos)[0], freq.get(pos)[1]);for (int i = 1; i <= most; ++i) {sequence.add(freq.get(pos)[0]);dfs(pos + 1, rest - i * freq.get(pos)[0]);}for (int i = 1; i <= most; ++i) {sequence.remove(sequence.size() - 1);}}