其他难题
33、搜索旋转排序数组
解题思路: 该段排序由于从中间划分,因此,必有一段是有序的 首先寻找其mid值,并将target与mid比较,若相等则返回即可。
若不相等,则target可能存在于左区间或者右区间,且两个区间必有一个是有序的。 首先若左区间有序{
目标存在于该区间内,则按照二分查找算法搜索 目标不在该区间内,则目标在右区间内或者不存在,因此left=mid+1转战右区间
}否则(即右区间有序){ 目标存在于该区间内,则按照二分查找算法搜索
目标不在该区间内,则目标在左区间内或者不存在,因此right=mid-1转战左区间 }
int left=0,right=nums.length-1;
while(left<=right) {
int mid=left+(right-left)/2;
if(nums[mid]==target) return mid;
if(nums[0]<=nums[mid]) {//左半边有序
if(nums[0]<=target &&nums[mid]>target) {//目标值在左半边
right=mid-1;
}else {
left=mid+1;
}
}else {//右半边有序
if(nums[right]>=target &&nums[mid]<target) {//目标值在右半边
left=mid+1;
}else {
right=mid-1;
}
}
}
return -1;
5、最长回文子串
中心扩散法
//中心扩散法
//index从0开始,记录最长子串
if(s.length()==0) return "";
if(s.length()==1) return s;
int startIndex=0,maxLength=0;
for(int i=0;i<s.length()-1;i++) {
int left=i-1,right=i+1;
//判断该元素临近是否有相似元素,并移动left和right
while((left>0)&&(s.charAt(left)==s.charAt(i))) {
left--;
}
while((right<=s.length()-1)&&(s.charAt(right)==s.charAt(i))) {
right++;
}
//同时移动left和right,看两端是否相同,若相同,则变化left和right
while((left>=0)&&(right<=s.length()-1)&&(s.charAt(left)==s.charAt(right))) {
left--;
right++;
}
left++;
right--;
if(right-left+1>maxLength) {
maxLength=right-left+1;
startIndex=left;
}
}
return s.substring(startIndex, startIndex+maxLength);
递归
最大公约数
public static int count(int m,int n){
if(m%n==0) return n;
else{
return count(n,m%n);
}
}
二叉搜索树的范围和 938
//递归
class Solution {
public int rangeSumBST(TreeNode root, int L, int R) {
if(root==null) return 0; //若为空,返回0
//当root的值比L还要小,则(L,R)范围内可能存在的只有其右子树,返回右子树上的在该范围内的值
if(root.val<L) return rangeSumBST(root.right,L,R);
if(root.val>R) return rangeSumBST(root.left,L,R);
//root符合标准,将root值加上以后再加上其左右子树返回过来的值
return root.val+rangeSumBST(root.left,L,R)+rangeSumBST(root.right,L,R);
}
}
递归乘法 面试题08.05
class Solution {
public int multiply(int A, int B) {
if(A==0 ||B==0) return 0;
return A+multiply(A,B-1);
}
}
二叉搜索树节点的最小距离 783
主要思路:对于二叉搜索树,其在中序遍历的时候是有序的,因此只需要不断记录在中序遍历时两个相邻节点的距离就可以得到最小距离
class Solution {
int min;
TreeNode pre;
public int minDiffInBST(TreeNode root) {
if(root==null ||(root.left==null &&root.right==null)) return 0;
//中序递归遍历
min=Integer.MAX_VALUE;
TreeNode pre=null;
dfs(root);
return min;
}
private void dfs(TreeNode root){
if(root ==null) return ;
dfs(root.left);
if(pre!=null){
min=Math.min(min,root.val-pre.val);
}
pre=root;
dfs(root.right);
}
}
最长同值路径 687 20200722
思路:递归
class Solution {
int max; //全局成员变量
public int longestUnivaluePath(TreeNode root) {
if(root==null||(root.left==null && root.right==null)) return 0;
max=Integer.MIN_VALUE;
dfs(root); //递归
return max;
}
private int dfs(TreeNode root){
if(root==null) return 0;
int left=dfs(root.left); //拿到该点左子树的高度,还不包括这个点
int right=dfs(root.right);//拿到该点右子树的高度,还不包括这个点
int arrleft=0;
int arrright=0;
//如果左节点的值与root相同,左子树高度+1
if(root.left!=null && root.val==root.left.val) arrleft+=(left+1);
//如果右节点的值与root相同,右子树高度+1
//贯穿一下
if(root.right!=null && root.val==root.right.val) arrright+=(right+1);
//max记录一下当前root的高度是否为最大,如果是的话,替换
max=Math.max(max,arrleft+arrright);
//但是该函数返回的时候,当前子树对父节点提供的最大长度为左右链中较大的一个
return Math.max(arrleft,arrright);
}
}
数值的整数次方
实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
示例 1:
输入: 2.00000, 10
输出: 1024.00000
class Solution {
public double myPow(double x, int n) {
if(x==0) return 0;
boolean flag=false;
double res=1.0;
long b=n;
if(b<0) {
x=1/x;
b=-b;
}
while(b>0){
if((b&1)==1) res*=x;
x=x*x;
b>>=1;
}
return res;
}
}
动态规划
礼物的最大价值
在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 12
解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
class Solution {
public int maxValue(int[][] grid) {
int m=grid.length;
int n=grid[0].length;
int[][] res=new int[m][n];
res[0][0]=grid[0][0];
for(int i=1;i<m;i++){
res[i][0]=res[i-1][0]+grid[i][0];
}
for(int i=1;i<n;i++){
res[0][i]=res[0][i-1]+grid[0][i];
}
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
res[i][j]=Math.max(res[i-1][j], res[i][j-1])+grid[i][j];
}
}
return res[m-1][n-1];
}
}
最小路径和
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
示例:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。
class Solution {
public int minPathSum(int[][] grid) {
if(grid.length==0) return 0;
int[][] res=new int[grid.length][grid[0].length];
res[0][0]=grid[0][0];
for(int i=1;i<grid.length;i++){
res[i][0]=res[i-1][0]+grid[i][0];
}
for(int i=1;i<grid[0].length;i++){
res[0][i]=res[0][i-1]+grid[0][i];
}
for(int i=1;i<grid.length;i++){
for(int j=1;j<grid[0].length;j++){
res[i][j]=Math.min(res[i-1][j],res[i][j-1])+grid[i][j];
}
}
return res[grid.length-1][grid[0].length-1];
}
}
三角形最小路径和
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int n=triangle.size();
int[][] res=new int[n][n];
res[0][0]=triangle.get(0).get(0);
for(int i=1;i<n;i++){
res[i][0]=res[i-1][0]+triangle.get(i).get(0);
for(int j=1;j<i;j++){
res[i][j]=Math.min(res[i-1][j],res[i-1][j-1])+triangle.get(i).get(j);
}
res[i][i]=res[i-1][i-1]+triangle.get(i).get(i);
}
int min=res[n-1][0];
for(int i=1;i<n;i++){
if(min>res[n-1][i]) min=res[n-1][i];
}
return min;
}
}
买卖一次 股票的最大利润
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
class Solution {
public int maxProfit(int[] prices) {
if(prices.length==0) return 0;
int[] res=new int[prices.length];
int min=prices[0];
res[0]=0;
for(int i=1;i<prices.length;i++){
min=Math.min(min, prices[i-1]);
res[i]=Math.max(prices[i]-min, res[i-1]);
}
return res[prices.length-1];
}
}
机器人路径问题
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?
输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。1. 向右 -> 向右 -> 向下2. 向右 -> 向下 -> 向右3. 向下 -> 向右 -> 向右
class Solution {
public int uniquePaths(int m, int n) {
int[][] res=new int[m][n];
for(int i=0;i<m;i++){
res[i][0]=1;
}
for(int i=0;i<n;i++){
res[0][i]=1;
}
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
res[i][j]=res[i-1][j]+res[i][j-1];
}
}
return res[m-1][n-1];
}
}
有障碍物的机器人路径问题
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
if(obstacleGrid.length==0)return 0;
int m=obstacleGrid.length;
int n=obstacleGrid[0].length;
int[][] res=new int[m][n];
if(obstacleGrid[0][0]==1) return 0;
else{
res[0][0]=1;
for(int i=1;i<m;i++){
if(obstacleGrid[i][0]==0){
res[i][0]=res[i-1][0];
}else{
res[i][0]=0;
}
}
for(int i=1;i<n;i++){
if(obstacleGrid[0][i]==0){
res[0][i]=res[0][i-1];
}else{
res[0][i]=0;
}
}
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
if(obstacleGrid[i][j]==0){
res[i][j]=res[i][j-1]+res[i-1][j];
}else{
res[i][j]=0;
}
}
}
}
return res[m-1][n-1];
}
}
完全平方数
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例 1:
输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4.
示例 2:
输入: n = 13
输出: 2
解释: 13 = 4 + 9.
class Solution {
public int numSquares(int n) {
int[] dp=new int[n+1];
for(int i=1;i<=n;i++) {
dp[i]=i;
for(int j=1;i-j*j>=0;j++) {
dp[i]=Math.min(dp[i], dp[i-j*j]+1);
}
}
return dp[n];
}
}
剪绳子
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
class Solution {
public int cuttingRope(int n) {
if(n==0|n==1) return 0;
if(n==2) return 1;
if(n==3) return 2;
int[] dp=new int[n+1];
dp[0]=0;
dp[1]=0;
dp[2]=1;
dp[3]=2;
for(int i=4;i<=n;i++){
int res=0;
for(int j=1;j<i;j++){
int res0=Math.max(j*dp[i-j], j*(i-j));
res=Math.max(res,res0);
}
dp[i]=res;
}
return dp[n];
}
}
最长上升子序列
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums.length<=1) return nums.length;
int[] res=new int[nums.length];
res[0]=1;
int max=1;
for(int i=1;i<nums.length;i++){
res[i]=1;
for(int j=0;j<i;j++){
if(nums[j]<nums[i]) res[i]=Math.max(res[i],res[j]+1);
}
if(res[i]>max) max=res[i];
}
return max;
}
}
判断子序列
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
class Solution {
public boolean isSubsequence(String s, String t) {
int s_index=0;
int t_index=0;
if(s.length()>t.length()) return false;
while(s_index<s.length()&&t_index<t.length()){
if(s.charAt(s_index)==t.charAt(t_index)){
s_index++;
t_index++;
}else{
t_index++;
}
}
if(s_index==s.length())return true;
return false;
}
}
回溯
技巧:
1、回溯用来解决组合问题
2、首先使用观察法观察结果集的子集排列顺序是否是有序的
【有序包括(1,2,3)(2,3)无序包括(2,1,3)(2,3,1)】
如果有序,无需设置辅助数据结构,但是递归函数中需要设置index值
如果无序,需要设置辅助数据结构,index一般要从头开始遍历
3、回溯法的主要节点在于“回”,即这一趟结束需要对刚添加进去的元素进行回退,以便进行下一次遍历
全排列 46
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
分析:组合;无序;
Perms(nums[0-n-1])={取出一个数字}+Perms(nums[0-n-1]-这个数字)
import java.util.ArrayList;
import java.util.List;
public class Permute {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> list =new ArrayList<>();
if(nums.length==0) return list;
if(nums.length==1) {
List<Integer> res=new ArrayList<>();
res.add(nums[0]);
list.add(new ArrayList<>(res));
return list;
}
boolean[] isVisited =new boolean[nums.length];
List<Integer> res=new ArrayList<>();
traceBack(nums,list,res,isVisited);
return list;
}
private void traceBack(int[] nums, List<List<Integer>> list, List<Integer> res, boolean[] isVisited) {
// TODO Auto-generated method stub
if(res.size()==nums.length) {
list.add(new ArrayList<>(res));
return ;
}
for(int i=0;i<nums.length;i++) {
if(!isVisited[i]) {
res.add(nums[i]);
isVisited[i]=true;
traceBack(nums, list, res, isVisited);
res.remove(res.size()-1);
isVisited[i]=false;
}
}
}
}
全排列 II 47
解题思路:首先写出全排列基础版的算法,再进行思考剪枝
在有重复数字时,首先要考虑的是排序,再对剩下的算法进行剪枝处理
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> list =new ArrayList<>();
if(nums.length==0) return list;
if(nums.length==1) {
List<Integer> res=new ArrayList<>();
res.add(nums[0]);
list.add(res);
return list;
}
List<Integer> res=new ArrayList<>();
boolean[] isVisited=new boolean[nums.length];
Arrays.sort(nums);
permuteDfs(nums,0,list,res,isVisited);
return list;
}
private void permuteDfs(int[] nums, int index, List<List<Integer>> list, List<Integer> res, boolean[] isVisited) {
// TODO Auto-generated method stub
if(res.size()==nums.length) {
for(int i=0;i<res.size();i++) {
System.out.print(res.get(i)+" ");
}
System.out.println();
list.add(new ArrayList<>(res));
return ;
}
for(int i=0;i<nums.length;i++) {
//当条件为i<nums.length-1 && nums[i]==nums[i+1] && isVisited[i+1] 时程序无法达到剪枝效果,主要是由于如此条件判断时,是将第一个枝剪掉,但是如果剪掉第一个枝,需要满足第一个枝已经被访问过,因此条件无法满足,程序错误
if(i>0 && nums[i]==nums[i-1] && isVisited[i-1]) continue;
if(!isVisited[i]) {
res.add(nums[i]);
isVisited[i]=true;
permuteDfs(nums, i, list, res, isVisited);
res.remove(res.size()-1);
isVisited[i]=false;
}
}
}
}
分割回文串
输入: “aab”
输出:
[
[“aa”,“b”],
[“a”,“a”,“b”]
]
class Solution {
public List<List<String>> partition(String s) {
List<List<String>> res=new ArrayList<>();
if(s.length()==0) return res;
List<String> list=new ArrayList<>();
backTrace(s,0,list,res);
return res;
}
private static void backTrace(String s,int index,List<String> list,List<List<String>> res){
if(s.length()==index){
res.add(new ArrayList<>(list));
return ;
}
for(int i=index;i<s.length();i++){
//判断字串是否为回文子串
if(!checkPalindRome(s,index,i)) continue;
list.add(s.substring(index,i+1));
backTrace(s,i+1,list,res);
list.remove(list.size()-1);
}
}
private static boolean checkPalindRome(String s,int left,int right){
while(left<right){
if(s.charAt(left)!=(s.charAt(right))){
return false;
}
left++;
right--;
}
return true;
}
}
字符串生成
输入:s = “abc”
输出:[“abc”,“acb”,“bac”,“bca”,“cab”,“cba”]
class Solution {
public String[] permutation(String s) {
Set<String> list=new HashSet<String>();
boolean[] isVisited=new boolean[s.length()];
if(s.length()==0) return null;
perm(s,0,"",isVisited,list);
String[] resString =new String[list.size()];
Iterator<String> it=list.iterator();
int i=0;
while(it.hasNext()) {
resString[i++]=it.next();
}
return resString;
}
private void perm(String s, int start, String res, boolean[] isVisited, Set<String> list) {
// TODO Auto-generated method stub
if(res.length()==s.length()) {
list.add(res);
return ;
}
for(int i=0;i<s.length();i++) {
if(!isVisited[i]) {
isVisited[i]=true;
perm(s, start+1, res+s.charAt(i), isVisited, list);
res=res.substring(0,res.length());
isVisited[i]=false;
}
}
}
}
括号生成
输入:n = 3
输出:[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
class Solution {
public List<String> generateParenthesis(int n) {
if(n==0) return new ArrayList<>(0); //n==0时直接return
List<String> res=new ArrayList<>();
int left_len=0;
int right_len=0;
dfs(left_len,right_len,n,res,"");
return res;
}
private void dfs(int left_len, int right_len, int n, List<String> res, String s) {
// TODO Auto-generated method stub
if(s.length()==2*n){ //递归结束条件
res.add(s);
return ;
}
if(left_len<n) dfs(left_len+1,right_len,n,res,s+'(');
if(right_len<left_len) dfs(left_len,right_len+1,n,res,s+')');
}
}
子集78
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
分析:组合,有序,长度不一样,需要传进去长度
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> list =new ArrayList<>();
if(nums.length==0) return list;
list.add(new ArrayList<>());
List<Integer> res=new ArrayList<>();
//从nums中取出的子集长度为1---n
for(int i=1;i<=nums.length;i++) {
backTrace(nums,i,0,res,list);
}
return list;
}
private void backTrace(int[] nums, int len, int index, List<Integer> res, List<List<Integer>> list) {
// res的长度等于len时,添加进list
if(res.size()==len) {
list.add(new ArrayList<>(res));
return;
}
//对于该循环,当将i添加进res后,由于有序,则后续再添加只考虑index值为i以后的元素
for(int i=index;i<nums.length;i++) {
res.add(nums[i]);
backTrace(nums, len, i+1, res, list);
res.remove(res.size()-1);
}
}
}
复原ip地址 93
class Solution {
public List<String> restoreIpAddresses(String s) {
List<String> list =new ArrayList<>();
if(s.length()<4) return list;
restoreDfs(s,0,0,list,"");
return list;
}
private void restoreDfs(String s,int index,int count,List<String> list,String res){
if(count==3 &&index<s.length()&& isValid(s.substring(index,s.length()))){
res+=s.substring(index,s.length());
list.add(res);
return ;
}
if(count>3 ||index>=s.length()) return ;
for(int i=index;i<s.length();i++){
if(index-i>2) break;
String subss=s.substring(index,i+1);
if(isValid(subss)){
res=res+s.substring(index,i+1)+'.';
restoreDfs(s,i+1,count+1,list,res);
res=res.substring(0,res.length()-(i-index+1)-1);
}
}
}
private boolean isValid(String subS){
if(subS.length()>3|| Integer.parseInt(subS)>255) return false;
if(subS.charAt(0)=='0' && subS.length()!=1) return false;
return true;
}
}
电话号码组合
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
class Main31 {
public List<String> letterCombinations(String digits) {
HashMap<Character,String> map=new HashMap<>();
map.put('2',"abc");
map.put('3',"def");
map.put('4',"ghi");
map.put('5',"jkl");
map.put('6',"mno");
map.put('7',"pqrs");
map.put('8',"tuv");
map.put('9',"wxyz");
List<String> list =new ArrayList<>();
String res="";
combitions(digits,list,res,0,map);
return list;
}
private void combitions(String digits,List<String> list, String res, int index, HashMap<Character, String> map){
if(index==digits.length()){
list.add(res);
return ;
}
String ss=map.get(digits.charAt(index));
for(int i=0;i<ss.length();i++){
combitions(digits,list,res+ss.charAt(i),index+1,map);
}
}
}
组合总和
输入:candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
import java.util.ArrayList;
import java.util.List;
public class Main32 {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> list=new ArrayList<>();
List<Integer> res=new ArrayList<>();
dfsSum(candidates,0,target,list,res);
return list;
}
private void dfsSum(int[] candidates,int index, int target,List<List<Integer>> list,List<Integer> res){
if(target==0){
list.add(new ArrayList<>(res));
return;
}
if(target<0) return ;
for(int i=index;i<candidates.length;i++){
res.add(candidates[i]);
dfsSum(candidates,i,target-candidates[i],list,res);
res.remove(res.size()-1);
}
}
}
2
2 2
2 2 2
2 2 2 2
2 2 2 3
2 2 2 6
2 2 2 7
2 2 3
2 2 6
2 2 7
2 3
2 3 3
2 3 6
2 3 7
2 6
2 7
3
3 3
3 3 3
3 3 6
3 3 7
3 6
3 7
6
6 6
6 7
7
组合总和||
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
if(candidates.length==0||target==0) return new ArrayList<>();
Arrays.sort(candidates);
List<List<Integer>> list=new ArrayList<>(); //记录所有结果
List<Integer> res=new ArrayList<>(); //记录该次的结果
backTrace(candidates,0,target,res,list);
return list;
}
private void backTrace(int[] candidates, int index, int target, List<Integer> res, List<List<Integer>> list) {
// TODO Auto-generated method stub
if(target==0){
list.add(new ArrayList<>(res));
return ;
}
if(target<0) return ;
for(int i=index;i<candidates.length;i++){
if(i>index && candidates[i]==candidates[i-1]) continue;//同一递归层不使用相同的元素
res.add(candidates[i]);
backTrace(candidates,i+1,target-candidates[i],res,list);
res.remove(res.size()-1);
}
}
}
单词搜索
board =
[
[‘A’,‘B’,‘C’,‘E’],
[‘S’,‘F’,‘C’,‘S’],
[‘A’,‘D’,‘E’,‘E’]
]
给定 word = “ABCCED”, 返回 true
给定 word = “SEE”, 返回 true
给定 word = “ABCB”, 返回 false
class Solution {
public boolean exist(char[][] board, String word) {
int row=board.length;
int col=board[0].length;
int[][] directions={{0,1},{1,0},{-1,0},{0,-1}};
boolean[][] isVisted=new boolean[row][col];
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
if(dfs1(i,j,board,word,0,directions,isVisted)) return true;
}
}
return false;
}
private boolean dfs1(int i, int j, char[][] board, String word, int index, int[][] directions, boolean[][] isVisted) {
// TODO Auto-generated method stub
if(word.length()-1==index) return board[i][j]==word.charAt(index);
if(word.charAt(index)==board[i][j]){
isVisted[i][j]=true;
for(int s=0;s<4;s++){
int newX=i+directions[s][0];
int newY=j+directions[s][1];
if(isValid(newX,newY,board)&&!isVisted[newX][newY]){
if(dfs1(newX, newY, board, word, index+1, directions, isVisted)) return true;
}
}
isVisted[i][j]=false;
}
return false;
}
private boolean isValid(int i, int j, char[][] board) {
// TODO Auto-generated method stub
if(i>=0 &&i<board.length &&j>=0 &&j<board[0].length) return true;
return false;
}
}
复原ip地址
输入: “25525511135”
输出: [“255.255.11.135”, “255.255.111.35”]
class Solution {
public List<String> restoreIpAddresses(String s) {
List<String> list =new ArrayList<>();
if(s.length()<4) return list;
restoreDfs(s,0,0,list,"");
return list;
}
private void restoreDfs(String s,int index,int count,List<String> list,String res){
if(count==3 &&index<s.length()&& isValid(s.substring(index,s.length()))){
res+=s.substring(index,s.length());
list.add(res);
return ;
}
if(count>3 ||index>=s.length()) return ;
for(int i=index;i<s.length();i++){
if(index-i>2) break;
String subss=s.substring(index,i+1);
if(isValid(subss)){
res=res+s.substring(index,i+1)+'.';
restoreDfs(s,i+1,count+1,list,res);
res=res.substring(0,res.length()-(i-index+1)-1);
}
}
}
private boolean isValid(String subS){
if(subS.length()>3|| Integer.parseInt(subS)>255) return false;
if(subS.charAt(0)=='0' && subS.length()!=1) return false;
return true;
}
}
简单
跳水板 面试题16.11
class Solution {
public int[] divingBoard(int shorter, int longer, int k) {
if(k==0) return new int[0];
int length=0;
if(shorter==longer) {
int[] res=new int[1];
res[0]=shorter*k;
return res;
}
int[] res=new int[k+1];
int deta=longer-shorter;
res[0]=shorter*k;
for(int i=1;i<res.length;i++){
res[i]=res[i-1]+deta;
}
return res;
}
}
数组
区间合并
class Mycompare implements Comparator<int[]>{
@Override
public int compare(int[] o1, int[] o2) {
// TODO Auto-generated method stub
return o1[0]-o2[0];
}
}
Scanner sc =new Scanner(System.in);
String[] s=sc.nextLine().split(" ");
int[][] nums=new int[s.length][2];
int i=0;
for(String ss:s){
nums[i][0]=Integer.parseInt(ss.split(",")[0]);
nums[i++][1]=Integer.parseInt(ss.split(",")[1]);
}
//Arrays.sort(nums,(a,b)->Integer.compare(a[0],b[0]));
// Comparator<int[]> cp = new Comparator<int[]>() {
//
// public int compare(int[] o1, int[] o2) {
// return o1[0]-o2[0];
// }
// };
Arrays.sort(nums,new Mycompare());
List<String> list =new ArrayList<>();
for(int j=0;j<nums.length;){
int left=nums[j][0];
int right=nums[j][1];
while(j<nums.length-1&&nums[j+1][0]<=right){
j++;
right=Math.max(right,nums[j][1]);
}
list.add(left+","+right);
j++;
}
for(int j=0;j<list.size();j++){
System.out.print(list.get(j)+' ');
}
超过数组的一半的数
import java.util.*;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
HashMap<Integer,Integer> map=new HashMap<>();
for(int i=0;i<array.length;i++){
if(map.containsKey(array[i])){
map.put(array[i],map.get(array[i])+1);
}else{
map.put(array[i],1);
}
}
int res=0;
Iterator<Map.Entry<Integer,Integer>> it =map.entrySet().iterator();
while(it.hasNext()){
Map.Entry<Integer,Integer> entry=it.next();
if(entry.getValue()>array.length/2)
{
res=entry.getKey();
break;
}
}
return res;
}
}
三数之和为0
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new ArrayList();
int len = nums.length;
if(nums == null || len < 3) return ans;
Arrays.sort(nums); // 排序
for (int i = 0; i < len ; i++) {
if(nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
int L = i+1;
int R = len-1;
while(L < R){
int sum = nums[i] + nums[L] + nums[R];
if(sum == 0){
ans.add(Arrays.asList(nums[i],nums[L],nums[R]));
while (L<R && nums[L] == nums[L+1]) L++; // 去重
while (L<R && nums[R] == nums[R-1]) R--; // 去重
L++;
R--;
}
else if (sum < 0) L++;
else if (sum > 0) R--;
}
}
return ans;
}
}
字符串
s.length()
s.charAt();
s.substring(beginIndex,endIndex);
两个大数字符串求和输出字符串
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc =new Scanner(System.in);
while(sc.hasNextLine()){
String s=sc.nextLine();
String s1=s.split(",")[0];
String s2=s.split(",")[1];
if(s1.length()==0|s2.length()==0) System.out.println(0);else{
//判断其最大公共子串
int res=0;
for(int i=0;i<s1.length();i++){
int max=0;
int iIndex=i;
for(int j=0;j<s2.length();j++){
if(iIndex<s1.length()){
if(s1.charAt(iIndex)!=s2.charAt(j)) continue;
else{
max++;
iIndex++;
}
}else{
break;
}
}
if(res<max) res=max;
}
System.out.println(res);
}
}
}
}
符号配对,如{}为true,{[}为false
注:stack栈为空时stack.peek() 报错
stack常用方法:stack.push()/stack.pop()/stack.isEmpty()
import java.util.Scanner;
import java.util.Stack;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(sc.hasNextLine()){
String s=sc.nextLine();
Stack<Character> stack=new Stack<>();
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='('||s.charAt(i)=='['){
stack.push(s.charAt(i));
}
if(s.charAt(i)==')'){
//判断栈顶元素,若是则出栈,否则返回错误
if(!stack.isEmpty() && stack.peek()=='('){
stack.pop();
}else{
System.out.println("false");
return ;
}
}
if(s.charAt(i)==']'){
if(!stack.isEmpty()&&(stack.peek()=='[')){
stack.pop();
}else{
System.out.println("false");
return ;
}
}
}
if(!stack.isEmpty()) System.out.println("false");
else System.out.println("true");
}
}
}
排序
插入排序
//插入排序 稳定
//第一轮从第二个位置开始,若值比前面的有序数组小往前遍历
private void insertSort(int[] nums) {
for(int i=1;i<nums.length;i++) {
int j;
int num=nums[i];
for(j=i-1;j>=0;j--) {
if(nums[j]>num) {
nums[j+1]=nums[j];
}else {
break;
}
}
nums[j+1]=num;
}
}
冒泡排序
//冒泡排序 稳定
for(int i=nums.length-1;i>=0;i--) {
for(int j=0;j<i;j++) {
if(nums[j]>nums[j+1]) {
int temp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=temp;
}
}
}
归并排序
//归并排序 稳定 递归写法
private static void mergeSort(int[] nums,int left,int right) {
if(left<right) {
int mid=(right+left)/2;
mergeSort(nums,left,mid);
mergeSort(nums,mid+1,right);
merge(nums,left,mid,right);
}
}
private static void merge(int[] nums, int left, int mid, int right) {
// TODO Auto-generated method stub
int[] temp=new int[right-left+1];
int i=left;
int j=mid+1;
int k=0;
while(i<=mid && j<=right) {
if(nums[i]<nums[j]) {
temp[k++]=nums[i++];
}else {
temp[k++]=nums[j++];
}
}
while(i<=mid) temp[k++]=nums[i++];
while(j<=right) temp[k++]=nums[j++];
k=left;
for(int s:temp) nums[k++]=s;
}
快速排序
//快速排序 不稳定 O(nlogn) 辅助空间 O(logn)~O(n)
public class quickSort {
public static void main(String[] args) {
int[] nums= {2,3,1,7,4,6,3};
quicksort(nums,0,nums.length-1);
for(int i:nums) System.out.println(i);
}
private static void quicksort(int[] nums, int left, int right) {
if(left<right) {
int pivot=partion(nums,left,right);
quicksort(nums,left,pivot-1);
quicksort(nums,pivot+1,right);
}
}
private static int partion(int[] nums, int left, int right) {
int pivot=nums[left];
while(left<right) {
while(left<right && nums[right]>pivot) right--;
if(left<right) nums[left++]=nums[right];
while(left<right && nums[left]<pivot) left++;
if(left<right) nums[right--]=nums[left];
}
nums[left]=pivot;
return left;
}
}
选择排序
//选择排序 不稳定,从小到大排序
//第一轮将第一个位置与遍历的剩下的位置比较,如果第一个位置大了就交换
//第二轮从第二个数组位置开始
for(int i=0;i<nums.length;i++){
for(int j=i+1;j<nums.length;j++){
if(nums[i]>nums[j]) swap;
}
}