目录
39.组合总和
22.括号生成
79.单词搜索
题意:
给你一个 无重复元素 的整数数组
candidates
和一个目标整数target
,找出candidates
中可以使数字和为目标数target
的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates
中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。对于给定的输入,保证和为
target
的不同组合数少于150
个。
【输入样例】candidates = [2,3,6,7], target = 7
【输出样例】[[2,2,3],[7]]
解题思路:
1、先对数组进行排序,排序之后可以更好的比较
2、定义二维数组res存储最终的结果
3、定义函数进行递归调用,函数接收的参数有(res数组,当前路径数组path,candidates,target,当前path的和sum,以及从第index个索引开始找)
4. 递归终止条件:当sum == target,找到一组结果,添加到res中并return结束当前的调用;
5. 否则,继续遍历,如果sum+当前值candidates[index]以及大于taget,则终止遍历,因为刚刚排序了,后面的值越来越大;如果不大于,则把condidates[index]添加到path中,继续向下遍历
6. 回溯操作,遍历完要移除路径path的最后一个元素,以便继续寻找可能的组合。
class Solution {
public List> combinationSum(int[] candidates, int target) {
List> res = new ArrayList<>();
Arrays.sort(candidates);
//从第0个元素开始找,当前路径和为0
searchPath(res,new ArrayList<>(),candidates,target,0,0);
return res;
}
public void searchPath(List> res, List path,int[] candidates, int target,int sum, int index){
//逮到了
if(sum == target){
res.add(new ArrayList<>(path));
return;
}
for(int i=index;i target) break;//是直接跳出循环噢
path.add(candidates[i]);
searchPath(res,path,candidates,target,sum+candidates[i],i);//sum要加上,可以重复选,所以还是i
path.remove(path.size()-1);//回溯回溯
}
}
}
时间: 击败了79.91%
内存: 击败了60.05%
题意:
数字
n
代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
【输入样例】n=3
【输出样例】["((()))","(()())","(())()","()(())","()()()"]
解题思路:
1、有效的括号要求是左括号的总数要小于等于右括号,才能够正确匹配。
2.、初始时,左括号的数量和右括号的数量都为n
3、当剩余的左括号数=右括号数时,下一位只能添加左括号,不然无法匹配
4、当剩余的左括号数<右括号数并且左括号数>0时,下一位可以添加左括号也可以添加右括号
5、递归结束的条件时剩余的左括号数=右括号数=0,没找到一组可能的序列,要进行回溯,删掉当前寻找序列的最后一位。ps:括号数量要记得加回去
class Solution {
public List generateParenthesis(int n) {
List res = new ArrayList<>();
if(n < 0){
return res;
}
search(res,new StringBuffer(),n,n);
return res;
}
public void search( List res, StringBuffer str, int left, int right){
if(left == 0 && right == 0){
res.add(str.toString());
return;
}
if(left == right){
search(res,str.append("("),--left,right);
//回溯,括号数量加回去
str.deleteCharAt(str.length()-1);
++left;
}else if(left < right){
if(left > 0){
search(res,str.append("("),--left,right);
str.deleteCharAt(str.length()-1);
++left;
}
search(res,str.append(")"),left,--right);
str.deleteCharAt(str.length()-1);
++right;
}
}
}
时间: 击败了72.95%
内存: 击败了75.13%
题意:
给定一个
m x n
二维字符网格board
和一个字符串单词word
。如果word
存在于网格中,返回true
;否则,返回false
。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
【输入样例】board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
【输出样例】true
解题思路:
1、由于同一个单元格内的字母不允许重复使用,定义二维boolean数据存储哪一个坐标元素已经使用
2、先遍历整个二维数组,寻找可能的开始元素board[i][j]
3、找到第一个单元格后,要上下左右寻找符合单词的第二个字母的单元格,没找到返回false,找到继续找第三、第四,同理,没找到要返回false,返回后,返回上一个符合要求的单元格(回溯),看其余三个方向是否有满足条件的
4、递归的终止条件是访问的单元格=单词字符串的长度(true),或者上文说的上下左右都不符合下一位(false)
本题解法参考:leetcode回溯算法经典例题——单词搜索
class Solution {
public boolean exist(char[][] board, String word) {
int m = board.length;
int n = board[0].length;
boolean[][] use = new boolean[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] == word.charAt(0)){
use[i][j] = true;
if (search(use,i, j, 1, word, board))
return true;
else use[i][j] = false;
}
}
}
return false;
}
public boolean search(boolean[][] use, int m, int n, int i, String word, char[][] board) {
if (i == word.length()) return true;
else {
if (m > 0 && board[m - 1][n] == word.charAt(i)&& !use[m - 1][n] ) {
use[m - 1][n] = true;
if (search(use, m - 1, n, i + 1, word, board))
return true;
else use[m - 1][n] = false;
}
if (m < board.length - 1&& board[m + 1][n] == word.charAt(i) && !use[m + 1][n] ) {
use[m + 1][n] = true;
if (search(use, m +1, n, i + 1, word, board))
return true;
else use[m + 1][n] = false;
}
if (n < board[0].length - 1 && board[m][n+1] == word.charAt(i) && !use[m][n+1] ) {
use[m][n+1] = true;
if (search(use, m, n+1, i + 1, word, board))
return true;
else use[m][n+1] = false;
}
if (n > 0 && board[m][n-1] == word.charAt(i) && !use[m][n-1] ) {
use[m][n-1] = true;
if (search(use, m, n-1, i + 1, word, board))
return true;
else use[m][n-1] = false;
}
return false;
}
}
}
时间: 击败了95.20%
内存: 击败了96.67%