46. 全排列
题意
给定一个不含重复数字的数组 nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
题解
因为是所有的排列组合,我们每一个位置都取一遍数组的所有元素看看有没有重复的即可
代码
import java.util.*;
public class Solution {
public static void main(String[] args) {
int []nums={1,2,3};
permute(nums);
}
static List<List<Integer>> ans;
public static List<List<Integer>> permute(int[] nums) {
ans=new ArrayList<>();
int []arr=new int[nums.length];
dfs(0,arr,nums);
return ans;
}
public static void dfs(int x,int []arr,int []nums){
if(x>=nums.length){
HashMap<Integer, Integer>mark=new HashMap<>();
ArrayList<Integer> brr=new ArrayList<>();
for(int i=0;i<arr.length;i++){
brr.add(arr[i]);
if(mark.containsKey(arr[i])){
return;
}
mark.put(arr[i],1);
}
ans.add(brr);
return;
}
else{
for(int i=0;i<nums.length;i++){
int f=arr[x];
arr[x]=nums[i];
dfs(x+1,arr,nums);
}
}
}
}
78. 子集
题意
给你一个整数数组 nums
,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
题解
我们这边引入数学的一个概念,一个大小为n的数组有2的n次方个子集,这个是怎么来的呢,我们举个例子,对于一个大小为3的数组,他的子集应该有8个,我们用1代表当前元素在子集中,0表示不在,也就是 000,001,010,011,100,101,110,111,有没有发现,将上述所有元素看作2进制,转化过来就是0,1,2,3,4,5,6,7了,那么枚举数字代表状态即可
代码
class Solution {
public List<List<Integer>> subsets(int[] nums) {
int x=nums.length;
int u=1<<x;
u--;
List<List<Integer>>ans=new ArrayList<>();
for(int i=0;i<=u;i++){
List<Integer>brr =new ArrayList<>();
for(int j=0;j<x;j++){
int f=1<<j;
if((i&f)!=0){
brr.add(nums[j]);
}
}
ans.add(brr);
}
return ans;
}
}
17. 电话号码的字母组合
题意
给定一个仅包含数字 2-9
的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
题解
跟第一题深度相似,我们dfs的时候带入当前节点的位置,然后还是每个节点都去枚举所有的数据,停止条件是超出数组范围
代码
import java.util.*;
public class Solution {
public static void main(String[] args) {
int []nums={1,2,3};
}
public List<String> letterCombinations(String digits) {
List<String>arr=new ArrayList<>();
arr.add("");
arr.add("");
arr.add("abc");
arr.add("def");
arr.add("ghi");
arr.add("jkl");
arr.add("mno");
arr.add("pqrs");
arr.add("tuv");
arr.add("wxyz");
List<String>ans=new ArrayList<>();
if(digits.length()==0){
return ans;
}
char []brr=digits.toCharArray();
char []crr=new char[brr.length];
dfs(ans,brr,arr,crr,0);
return ans;
}
public static void dfs(List<String>ans,char []brr,List<String>arr,char []crr,int x){
if(x>=brr.length){
String s="";
for(int i=0;i<crr.length;i++){
s=s+crr[i];
}
ans.add(s);
}
else{
int f=brr[x]-'0';
for(int j=0;j<arr.get(f).length();j++){
crr[x]=arr.get(f).charAt(j);
dfs(ans,brr,arr,crr,x+1);
}
}
}
}
39. 组合总和
题意
给你一个 无重复元素 的整数数组 candidates
和一个目标整数 target
,找出 candidates
中可以使数字和为目标数 target
的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates
中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target
的不同组合数少于 150
个。
题解
本来没想到怎么做,翻了一下题解,发现是剪枝dfs,那就是跟之前的做法一样了,也就是每次从头开始深度搜索元素,当和大于target的时候停止即可
代码
import java.util.*;
public class Solution {
public static void main(String[] args) {
int []nums={1,2,3};
}
static List<List<Integer>>ans;
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
int []arr=new int[target+1];
ans=new ArrayList<>();
dfs(arr,0,target,0,candidates);
return ans;
}
public static void dfs(int []arr,int x,int y,int j,int []crr){
if(x>y){
return;
}
else if(x==y){
List<Integer>brr=new ArrayList<>();
for(int i=0;i<j;i++){
if(i!=0&&arr[i]<arr[i-1]){
return;
}
brr.add(arr[i]);
}
ans.add(brr);
return;
}
else{
for(int i=0;i<crr.length;i++){
arr[j]=crr[i];
dfs(arr,x+crr[i],y,j+1,crr);
}
}
}
}
22. 括号生成
题意
数字 n
代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
题解
如果你不会判断括号序列,请看题主的之前的栈篇,我们还是通过子集枚举,枚举所有的左端括号的位置,用1代替,0代替右边括号,最后看看是不是括号序列即可
代码
import java.util.*;
public class Solution {
public static void main(String[] args) {
int []nums={1,2,3};
generateParenthesis(3);
}
public static int getx(int y){
int sum=0;
while(y>0){
if((y&1)!=0){
sum++;
}
y>>=1;
}
return sum;
}
public static List<String> generateParenthesis(int n) {
n=n*2;
int u =1<<n;
u--;
List<String>ans=new ArrayList<>();
for(int i=0;i<=u;i++){
int z=i;
if(getx(z)==n/2){
String s="";
for(int j=0;j<=n-1;j++){
int f=1<<j;
if((f&i)!=0){
s=s+"(";
}
else{
s=s+")";
}
}
if(isValid(s)){
ans.add(s);
}
}
}
return ans;
}
public static boolean isValid(String s) {
char []arr=s.toCharArray();
Deque<Character> stack =new LinkedList<>();
for(int i=0;i<arr.length;i++){
if(arr[i]=='('||arr[i]=='['||arr[i]=='{'){
stack.push(arr[i]);
}
else if(stack.isEmpty()){
return false;
}
else{
char c=stack.peek();
if(arr[i]==')'){
if(c!='('){
return false;
}
stack.pop();
}
}
}
if(stack.size()!=0){
return false;
}
return true;
}
}
79. 单词搜索
题意
给定一个 m x n
二维字符网格 board
和一个字符串单词 word
。如果 word
存在于网格中,返回 true
;否则,返回 false
。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
题解
也是比较板子的题目,我们先建立个数组代表走的四个方向,然后继续建立数组代表当前位置来没有来过,那么我们进行dfs,看看每一个位置能不能对应上当前的字符串的位置,如果对应上,标记走过,继续向下dfs,如果不可以就停止,结束条件是超过字符串长度
代码
import java.util.*;
public class Solution {
public static void main(String[] args) {
char arr[][]={{'A','B','C','E'},{'S','F','C','S'},
{'A','D','E','E'}
};
String s="ABCB";
exist(arr,s);
}
static int n;
static int m;
static int mark[][]=new int[20][20];
static boolean ans=false;
static int []zou1={0,1,-1,0,0};
static int []zou2={0,0,0,1,-1};
public static boolean exist(char[][] board, String word) {
n=board.length;
m=board[0].length;
char []s=word.toCharArray();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
mark[i][j]=0;
}
}
ans=false;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(ans){
return ans;
}
if(board[i][j] == s[0]){
mark[i][j]=1;
dfs(i,j,1,s,board);
mark[i][j]=0;
}
}
}
System.out.println(ans);
return ans;
}
public static void dfs(int i,int j,int wei,char []s,char [][]board){
if(wei>=s.length){
ans=true;
}
if(ans){
return;
}
for(int i1=1;i1<=4;i1++){
int x1=i+zou1[i1];
int y1=j+zou2[i1];
if(x1<0||x1>=n||y1<0||y1>=m||mark[x1][y1]==1){
continue;
}
if(board[x1][y1]==s[wei]){
mark[x1][y1]=1;
dfs(x1,y1,wei+1,s,board);
mark[x1][y1]=0;
}
}
}
}
131. 分割回文串
题意
给你一个字符串 s
,请你将 s
分割成一些 子串,使每个子串都是 回文串 。返回 s
所有可能的分割方案。
题解
额,枚举最后结束字符的位置即可,子集枚举
举例 aabb,当前二进制如果为0101,那么就是aa bb,如果是1111,就是a a b b ,然后判断是不是回文即可
代码
import java.util.*;
public class Solution {
public static void main(String[] args) {
int []nums={1,2,3};
String s="aab";
partition(s);
}
public static List<List<String>> partition(String s) {
List<List<String>>ans=new ArrayList<>();
char []brr=s.toCharArray();
int n=s.length();
int u=1<<n;
u--;
int f3=1<<(n-1);
for(int i=1;i<=u;i++){
if((i&f3)==0){
continue;
}
boolean mark=true;
String s1="";
List<String>crr=new ArrayList<>();
for(int j=0;j<n;j++){
int f=1<<j;
if((f&i)!=0){
s1=s1+brr[j];
if(!check(s1)){
mark=false;
break;
}
crr.add(s1);
s1="";
}
else{
s1=s1+brr[j];
}
}
if(mark){
ans.add(crr);
}
}
return ans;
}
public static boolean check(String s){
char []arr=s.toCharArray();
for(int i=0;i<arr.length;i++){
if(arr[i]!=arr[arr.length-i-1]){
return false;
}
}
return true;
}
}
51. N 皇后
题意
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将 n
个皇后放置在 n×n
的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n
,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q'
和 '.'
分别代表了皇后和空位。
题解
作为hard题并没有hard题的难度
首先我们看看规则,每一行不可以有超过两个,但是至少一个,那么你可以提前把这些状态找出来,肯定是2 4 8 16 ...... 换成二进制就是 00001 00010 00100 ,01000,10000,然后你每次dfs,每一行的状态就从当前里面取出来就可以了,但是还有一个情况,怎么满足斜着也没有,你会发现,如果是沿着y=x的方向的话,他的x-y的差值是固定的,相同,沿着y=-x的方向,y+x的和是相同的,最后枚举出状态判断一下即可
代码
import java.util.*;
public class Solution {
public static void main(String[] args) {
int []nums={1,2,3};
solveNQueens(4);
}
static int[]arr={1,2,4,8,16,32,64,128,256,512,1024,2048};
static int x=0;
public static List<List<String>> solveNQueens(int n) {
x=n;
int []mark=new int[20];
List<List<String>>ans=new ArrayList<>();
int []brr=new int[20];
dfs(ans,1,brr,mark);
return ans;
}
public static int getx(int y){
int sum=0;
while(y!=1){
sum++;
y>>=1;
}
return sum;
}
public static void dfs(List<List<String>>ans,int wei,int []brr,int []mark){
if(wei>x){
HashMap<Integer,Integer>a=new HashMap<>();
HashMap<Integer,Integer>b=new HashMap<>();
HashMap<Integer,Integer>c=new HashMap<>();
for(int i=1;i<=x;i++){
if(a.containsKey(brr[i])){
return;
}
a.put(brr[i],1);
int f=brr[i];
int f1=getx(f);
if(b.containsKey(i+f1)){
return;
}
b.put(i+f1,1);
f=brr[i];
f1=getx(f);
if(c.containsKey(i-f1)){
return;
}
c.put(i-f1,1);
}
List<String>crr=new ArrayList<>();
for(int i=1;i<=x;i++){
String s="";
for(int j=1;j<=x;j++){
int f=1<<j;
if((f&brr[i])!=0){
s=s+"Q";
}
else{
s=s+".";
}
}
crr.add(s);
}
ans.add(crr);
return;
}
for(int i=1;i<=x;i++){
if(mark[i]!=0){
continue;
}
brr[wei]=arr[i];
mark[i]=1;
dfs(ans,wei+1,brr,mark);
mark[i]=0;
}
}
}
如果有不理解的可以问题主