一:排列问题
题目描述:
二:组合问题
题目描述:给定一个无重复元素的数组 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。candidates
中的数字可以无限制重复被选取。
说明:
- 所有数字(包括
target
)都是正整数。 - 解集不能包含重复的组合。
示例 1:
输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:输入: candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
import java.util.ArrayList;
import java.util.List;
class Solution {
List<List<Integer>> res=new ArrayList<List<Integer>>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
// List<List<Integer>> res=new ArrayList<List<Integer>>();
if(candidates==null)
return res;
ArrayList<Integer> list=new ArrayList<Integer>();
f(target,0,candidates,list);
return res;
}
public void f(int sum, int index,int[] num, ArrayList<Integer> list){
//递归终止条件:sum值为0 即找到一个解;或者超过了预期的sum 或者到了num的边界
if(sum==0){
res.add(new ArrayList(list));
return;
}
if(sum<0||index==num.length)
return;
sum-=num[index];
list.add(num[index]);
f(sum, index, num, list);
//相当于回退 当前计算中 把inde为下标的数字刨除 从index+1开始计算值为sum的组合
sum+=num[index];
list.remove(list.size()-1);
f(sum,index+1,num,list);
}
}
三:二维平面上使用回溯
题目描述:word search
class Solution {
int[][] step={{-1,0},{0,1},{1,0},{0,-1}};//用于在四个方向上的位移的辅助数组
public boolean exist(char[][] board, String word) {
//利用回溯的思想
int m=board.length;
int n=board[0].length;
boolean[][] visited=new boolean[m][n];
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
if(search(board,word,0,i,j,visited))
return true;
}
}
return false;
}
//在board中寻找word,从startx startY的位置寻找word的下标为index的字符
public boolean search(char[][] board, String word, int index, int startX, int startY,boolean[][] visited){
//递归终止条件,即当搜索到了word的最后一位时,检查当前所在位置是否与最后一位的字符相等
if(index==word.length()-1)
return board[startX][startY]==word.charAt(index);
//递归过程 如果当前位置符合条件 则递归搜索其周围四个位置上是否有下一个位的字符
if(board[startX][startY]==word.charAt(index)){
visited[startX][startY]=true;
for(int k=0; k<4; k++){
int newX=startX+step[k][0];
int newY=startY+step[k][1];
//下一步的位置没越界且未被访问过 且值为word下一位的值
if(inArea(newX,newY,board)==true && visited[newX][newY]==false && search(board,word,index+1,newX,newY,visited))
return true;
}
visited[startX][startY]=false;//回溯
}
//当前位置就不行 则本次函数直接返回false
return false;
}
//判断是否越界的函数
public boolean inArea(int x,int y,char[][] board){
return x>=0 && x<board.length && y>=0 && y<board[0].length;
}
}
四:经典问题:floodfill
题目描述:岛屿的个数
给定一个由 '1'
(陆地)和 '0'
(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。
示例 1:
输入:
11110
11010
11000
00000
输出: 1
示例 2:
输入:
11000
11000
00100
00011
输出: 3
class Solution {
int[][] d={{1,0},{0,1},{0,-1},{-1,0}};//向四个方向的位移
int count=0;
public int numIslands(char[][] grid) {
if(grid==null)
return 0;
//floodfill问题
int m=grid.length;
int n=0;
if(m>0)
n=grid[0].length;
boolean[][] visited=new boolean[m][n];//用来标识某一位是否已经被标记过的数组
for(int i=0; i<m ;i++){
for(int j=0; j<n; j++){
if(grid[i][j]=='1' && visited[i][j]==false){
count++;
f(grid,i,j,visited);
}
}
}
return count;
}
//标记从startX startY位置周围四个位置的数字的函数,如果是岛屿 就标记visited为true
public void f(char[][] grid, int startX, int startY, boolean[][] visited){
visited[startX][startY]=true;
for(int i=0; i<4; i++){
int newX=startX+d[i][0];
int newY=startY+d[i][1];
//如果下一个位置未被访问 且未越界 且是岛屿 则递归对其周围元素进行标记
if(inArea(newX,newY,grid)==true && visited[newX][newY]==false && grid[newX][newY]=='1'){
f(grid, newX, newY, visited);
}
//因为即使退出函数 也不用对标记过的数字进行回退 所以这里不用做什么
}
}
public boolean inArea(int x, int y, char[][] grid){
return x>=0 && x<grid.length && y>=0 && y<grid[0].length;
}
}
题目描述:surrouded regions:
Given a 2D board containing'X'and'O', capture all regions surrounded by'X'.
A region is captured by flipping all'O's into'X's in that surrounded region .
For example,
X X X X
X O O X
X X O X
X O X X
After running your function, the board should be:
X X X X
X X X X
X X X X
X O X X
public class Solution {
int[][] d={{1,0},{0,1},{-1,0},{0,-1}};//向四个方向进行位移的数组
public void solve(char[][] board) {
//floodfill问题 与计算岛屿个数那道题差不多 思路是找到不被包围的位置进行标记
//标记是否要被翻转的二维数组
if(board==null)
return;
int m=board.length;
int n=0;
if(m>0)
n=board[0].length;
boolean[][] label=new boolean[m][n];
//被翻转的O一定在边界 或者与边界的O直接或间接地相连
//以边界的O为突破口 将一定不能被翻转的O标记上 然后把剩余的O翻转
//第一列
for(int i=0; i<m; i++){
if(board[i][0]=='O'){
f(board,i,0,label);
}
}
//第一行
for(int i=0; i<n; i++){
if(board[0][i]=='O'){
f(board,0,i,label);
}
}
//最后一列
for(int i=1; i<m; i++){
if(board[i][n-1]=='O'){
f(board,i,n-1,label);
}
}
//最后一行
for(int i=1; i<n; i++){
if(board[m-1][i]=='O'){
f(board,m-1,i,label);
}
}
//标记完成 进行翻转
for(int i=0; i<m; i++)
for(int j=0; j<n; j++){
if(label[i][j]==false && board[i][j]=='O')
board[i][j]='X';
}
}
public void f(char[][] board, int startX, int startY,boolean[][] label){
label[startX][startY]=true;//标记当前位置
for(int i=0; i<4; i++){
int newX=startX+d[i][0];
int newY=startY+d[i][1];
if(inArea(newX,newY,board)==true && board[newX][newY]=='O' && label[newX][newY]==false){
f(board, newX, newY,label);
}
}
}
public boolean inArea(int x, int y, char[][] board){
return x>=0 && x<board.length && y>=0 && y<board[0].length;
}
}
五:N-Queens问题: