本博客文章(学习笔记)导航 (点击这里访问)
NC1 大数之和
描述
以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回。
数据范围:len(s),len(t),len(s),len(t)≤100000,字符串仅由'0'~‘9’构成
要求:时间复杂度 O(n)
示例1
输入:"1","99"
返回值:"100"
说明:1+99=100
示例2
输入:"114514",""
返回值:"114514"
思路:
合并数组
import java. util. * ;
public class Solution {
public String solve ( String s, String t) {
if ( s. equals ( "" ) || s== null ) return t;
if ( t. equals ( "" ) || t== null ) return s;
s= strReverse ( s) ;
t= strReverse ( t) ;
char [ ] s0= s. toCharArray ( ) ;
char [ ] s1= t. toCharArray ( ) ;
int fornum= s0. length>= s1. length? s1. length: s0. length;
StringBuffer sb= new StringBuffer ( ) ;
int add= 0 ;
for ( int i= 0 ; i< fornum; i++ ) {
Integer num1= ( int ) ( s. charAt ( i) - '0' ) ;
Integer num2= ( int ) ( t. charAt ( i) - '0' ) ;
Integer sum= num2+ num1+ add;
sb. append ( sum% 10 ) ;
add= sum/ 10 ;
}
if ( s0. length> fornum) {
for ( int i= fornum; i< s0. length; i++ ) {
Integer num1= ( int ) ( s. charAt ( i) - '0' ) ;
Integer sum= num1+ add;
sb. append ( sum% 10 ) ;
add= sum/ 10 ;
}
}
if ( s1. length> fornum) {
for ( int i= fornum; i< s1. length; i++ ) {
Integer num1= ( int ) ( t. charAt ( i) - '0' ) ;
Integer sum= num1+ add;
sb. append ( sum% 10 ) ;
add= sum/ 10 ;
}
}
if ( add!= 0 ) sb. append ( add+ "" ) ;
sb= sb. reverse ( ) ;
return sb. toString ( ) ;
}
public String strReverse ( String str) {
if ( str. length ( ) == 0 || str. length ( ) == 1 ) return str;
StringBuilder sb= new StringBuilder ( str) ;
sb. reverse ( ) ;
return sb. toString ( ) ;
}
}
NC7 买卖股票的最佳时机(一)
描述
假设你有一个数组prices,长度为n,其中prices[i]是股票在第i天的价格,请根据这个价格数组,返回买卖股票能获得的最大收益
1.你可以买入一次股票和卖出一次股票,并非每天都可以买入或卖出一次,总共只能买入和卖出一次,且买入必须在卖出的前面的某一天
2.如果不能获取到任何利润,请返回0
3.假设买入卖出均无手续费
数据范围: 0≤n≤10000,0≤val≤10000
要求:空间复杂度 O(1),时间复杂度 O(n)
示例1
输入:[8,9,2,5,4,7,1]
返回值:5
示例2
输入:[2,4,1]
返回值:2
示例3
输入:[3,2,1]
返回值:0
思路1:
找到差值最大的两个数,后面的那个数比前面的大
思路2:
动态规划
当天持有股票:前天持有股票或者今天刚买
当天不持有股票:前天不持有股票或者前天持有今天刚卖
思路1 :
import java. util. * ;
public class Solution {
public int maxProfit ( int [ ] prices) {
if ( prices. length< 2 ) return 0 ;
int max= 0 ;
for ( int i= 0 ; i< prices. length- 1 ; i++ ) {
int n1= prices[ i] ;
for ( int j= i+ 1 ; j< prices. length; j++ ) {
max= Math . max ( max, prices[ j] - n1) ;
}
}
return max;
}
}
思路2 :
import java. util. * ;
public class Solution {
public int maxProfit ( int [ ] prices) {
int [ ] [ ] dp= new int [ prices. length] [ 2 ] ;
dp[ 0 ] [ 0 ] = 0 ;
dp[ 0 ] [ 1 ] = - prices[ 0 ] ;
for ( int i= 1 ; i< prices. length; i++ ) {
dp[ i] [ 0 ] = Math . max ( dp[ i- 1 ] [ 0 ] , dp[ i- 1 ] [ 1 ] + prices[ i] ) ;
dp[ i] [ 1 ] = Math . max ( dp[ i - 1 ] [ 1 ] , - prices[ i] ) ;
}
return dp[ prices. length- 1 ] [ 0 ] ;
}
}
NC12 重建二叉树
描述
给定节点数为 n 二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。
提示:
1.vin.length == pre.length
2.pre 和 vin 均无重复元素
3.vin出现的元素均出现在 pre里
4.只需要返回根结点,系统会自动输出整颗树做答案对比
数据范围:0n≤2000,节点的值 0≤val≤10000
要求:空间复杂度 O(n),时间复杂度 O(n)
import java. util. * ;
public class Solution {
static HashMap < Integer , Integer > map= new HashMap < Integer , Integer > ( ) ;
static int [ ] pre;
public TreeNode reConstructBinaryTree ( int [ ] pre, int [ ] vin) {
this . pre= pre;
for ( int i= 0 ; i< vin. length; i++ ) {
map. put ( vin[ i] , i) ;
}
return recur ( 0 , 0 , vin. length- 1 ) ;
}
public TreeNode recur ( int pre_index, int vin_left, int vin_right) {
if ( vin_left> vin_right) return null ;
TreeNode root= new TreeNode ( pre[ pre_index] ) ;
int root_index= map. get ( pre[ pre_index] ) ;
root. left= recur ( pre_index+ 1 , vin_left, root_index- 1 ) ;
root. right= recur ( pre_index+ root_index- vin_left+ 1 , root_index+ 1 , vin_right) ;
return root;
}
}
NC18 顺时针旋转数组
n为矩阵的长和宽
输入:[[1,2,3],[4,5,6],[7,8,9]],3
返回值:[[7,4,1],[8,5,2],[9,6,3]]
思路:
直接求解res[j][n-i-1]=mat[i][j]
import java. util. * ;
public class Solution {
public int [ ] [ ] rotateMatrix ( int [ ] [ ] mat, int n) {
int [ ] [ ] res= new int [ n] [ n] ;
for ( int i= 0 ; i< n; i++ ) {
for ( int j= 0 ; j< n; j++ ) {
res[ j] [ n- i- 1 ] = mat[ i] [ j] ;
}
}
return res;
}
}
NC 22 合并两个有序数组
描述
给出一个有序的整数数组 A 和有序的整数数组 B ,请将数组 B 合并到数组 A 中,变成一个有序的升序数组
数据范围: 0≤n,m≤100,|Ai| <=100,|Bi| <= 100
注意:
1.保证 A 数组有足够的空间存放 B 数组的元素, A 和 B 中初始的元素数目分别为 m 和 n,A的数组空间大小为 m+n
2.不要返回合并的数组,将数组 B 的数据合并到 A 里面就好了
3. A 数组在[0,m-1]的范围也是有序的
示例1
输入:[4,5,6],[1,2,3]
返回值:[1,2,3,4,5,6]
说明:
A数组为[4,5,6],B数组为[1,2,3],后台程序会预先将A扩容为[4,5,6,0,0,0],B还是为[1,2,3],m=3,n=3,传入到函数merge里面,然后请同学完成merge函数,将B的数据合并A里面,最后后台程序输出A数组
示例2
输入:[1,2,3],[2,5,6]
返回值:[1,2,2,3,5,6]
思路:
1 倒着填充,谁大填谁
2 当A没填完直接返回
3 B没填充完,再开一个for循环填充即可
import java. util. * ;
public class Solution {
public void merge ( int A [ ] , int m, int B [ ] , int n) {
int left= m- 1 , right= n- 1 ;
for ( int i= A . length- 1 ; i>= 0 && left>= 0 && right>= 0 ; i-- ) {
if ( A [ left] > B [ right] ) {
A [ i] = A [ left] ;
left-- ;
} else {
A [ i] = B [ right] ;
right-- ;
}
}
if ( right!= - 1 ) {
for ( int i= right; i>= 0 ; i-- ) {
A [ i] = B [ i] ;
}
}
}
}
NC 27 集合的所有子集(一)
描述
现在有一个没有重复元素的整数集合S,求S的所有子集
注意:
你给出的子集中的元素必须按升序排列
给出的解集中不能出现重复的元素
数据范围:1≤n≤5,集合中的任意元素满足 ∣val∣≤10
要求:空间复杂度 O(n!),时间复杂度 O(n!)
示例1
输入:[1,2,3]
返回值:[[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]
示例2
输入:[]
返回值:[]
思路:
1 回溯
2 终止条件:index越界开始添加
3 每个index有两个选择:添加和不添加
import java. util. * ;
public class Solution {
public ArrayList < ArrayList < Integer > > subsets ( int [ ] S ) {
ArrayList < ArrayList < Integer > > res= new ArrayList < ArrayList < Integer > > ( ) ;
if ( S . length== 0 ) return res;
recur ( res, S , new ArrayList < Integer > ( ) , 0 ) ;
return res;
}
public void recur ( ArrayList < ArrayList < Integer > > res, int [ ] S , ArrayList < Integer > temp, int index) {
if ( index>= S . length) {
res. add ( new ArrayList < Integer > ( temp) ) ;
return ;
}
temp. add ( S [ index] ) ;
recur ( res, S , temp, index+ 1 ) ;
temp. remove ( temp. size ( ) - 1 ) ;
recur ( res, S , temp, index+ 1 ) ;
}
}
NC 29 二维数组中查找
描述
在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
[[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]]
给定 target = 7,返回 true。
给定 target = 3,返回 false。
数据范围:矩阵的长宽满足0≤n,m≤500 , 矩阵中的值满足0≤val≤10
进阶:空间复杂度 O(1),时间复杂度 O(n+m)
示例1
输入:7,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]
返回值:true
说明:
存在7,返回true
示例2
输入:1,[[2]]
返回值:false
思路:
可以看成一个二叉搜索树
以右上角的值为根节点
public class Solution {
public boolean Find ( int target, int [ ] [ ] array) {
int i= 0 , j= array[ 0 ] . length- 1 ;
return judge ( target, array, i, j) ;
}
public boolean judge ( int target, int [ ] [ ] array, int i, int j) {
if ( i>= array. length|| j< 0 ) return false ;
if ( target== array[ i] [ j] ) {
return true ;
} else if ( target> array[ i] [ j] ) {
return judge ( target, array, i+ 1 , j) ;
} else {
return judge ( target, array, i, j- 1 ) ;
}
}
}
NC 30 缺失的第一个数字
描述
给定一个无重复元素的整数数组nums,请你找出其中没有出现的最小的正整数
进阶: 空间复杂度 O(1),时间复杂度 O(n)
数据范围:
-2^31<=nums[i]<=2^31-1
0<=len(nums)<=5*10^5
示例1
输入:[1,0,2]
返回值:3
示例2
输入:[-2,3,4,1,5]
返回值:2
示例3
输入:[4,5,6,8,9]
返回值:1
思路1:
HashSet 保存,再次遍历1-nums.length
时间复杂度:O(n)
空间复杂度:O(n)
思路2:
排序,从第一个正数处开始判断
时间复杂度:O(nlog(n))
空间复杂度:O(1)
思路1 :
import java. util. * ;
public class Solution {
public int minNumberDisappeared ( int [ ] nums) {
HashSet < Integer > set= new HashSet ( ) ;
for ( int i: nums) set. add ( i) ;
for ( int i= 1 ; i<= nums. length; i++ ) {
if ( ! set. contains ( i) ) {
return i;
}
}
return nums. length+ 1 ;
}
}
思路2 :
import java. util. * ;
public class Solution {
public int minNumberDisappeared ( int [ ] nums) {
Arrays . sort ( nums) ;
int noSub= - 1 ;
for ( int i= 0 ; i< nums. length; i++ ) {
if ( nums[ i] > 0 && noSub< 0 ) noSub= i;
if ( nums[ i] > 0 ) {
if ( nums[ i] != ( i- noSub+ 1 ) ) return i- noSub+ 1 ;
}
}
return nums[ nums. length- 1 ] + 1 ;
}
}
NC 36 在两个长度相等的排序数组中找到上中位数
描述
给定两个递增数组arr1和arr2,已知两个数组的长度都为N,求两个数组中所有数的上中位数。
上中位数:假设递增序列长度为n,为第n/2个数
数据范围:1≤n≤10,0≤arr≤10^9
要求:时间复杂度 O(n),空间复杂度 O(1)
进阶:时间复杂度为O(logN),空间复杂度为O(1)
示例1
输入:[1,2,3,4],[3,4,5,6]
返回值:3
说明:总共有8个数,上中位数是第4小的数,所以返回3。
示例2
输入:[0,1,2],[3,4,5]
返回值:2
说明:总共有6个数,那么上中位数是第3小的数,所以返回2
思路:
相当于合并数组
找到合并后的第arr1.length个元素
import java. util. * ;
public class Solution {
public int findMedianinTwoSortedAray ( int [ ] arr1, int [ ] arr2) {
if ( arr1. length== 1 ) return Math . min ( arr1[ 0 ] , arr2[ 0 ] ) ;
int aim= arr1. length;
int Nom = 0 ;
int left= 0 , right= 0 ;
while ( left< arr1. length&& right< arr2. length) {
if ( arr1[ left] < arr2[ right] ) {
left++ ;
Nom ++ ;
if ( Nom == aim) return arr1[ left- 1 ] ;
} else {
right++ ;
Nom ++ ;
if ( Nom == aim) return arr2[ right- 1 ] ;
}
}
while ( left< arr1. length) {
left++ ;
Nom ++ ;
if ( Nom == aim) return arr1[ left- 1 ] ;
}
while ( right< arr2. length) {
right++ ;
Nom ++ ;
if ( Nom == aim) return arr2[ right- 1 ] ;
}
return 0 ;
}
}
NC 37合并区间
描述:给出一组区间,请合并所有重叠的区间。请保证合并后的区间按区间起点升序排列。
数据范围:区间组数0 ≤n≤1000 ,区间内 的值都满足0 ≤val≤10000
要求:空间复杂度 O ( n) ,时间复杂度 O ( nlogn)
进阶:空间复杂度 O ( val) ,时间复杂度O ( val)
示例1
输入:[ [ 10 , 30 ] , [ 20 , 60 ] , [ 80 , 100 ] , [ 150 , 180 ] ]
返回值:[ [ 10 , 60 ] , [ 80 , 100 ] , [ 150 , 180 ] ]
示例2
输入:[ [ 0 , 10 ] , [ 10 , 20 ] ]
返回值:[ [ 0 , 20 ] ]
思路:
1 排序(start从小到大)
2 前后指针 比较i的end和(i+1)的start和end的值进行合并
3 删除多余的元素
import java. util. * ;
public class Solution {
public ArrayList < Interval > merge ( ArrayList < Interval > intervals) {
ArrayList < Interval > res= new ArrayList < > ( ) ;
if ( intervals. size ( ) < 2 ) return intervals;
Collections . sort ( intervals, ( a, b) -> a. start- b. start) ;
for ( int i= 0 ; i< intervals. size ( ) - 1 ; i++ ) {
if ( intervals. get ( i) . end>= intervals. get ( i+ 1 ) . start) {
intervals. set ( i+ 1 , new Interval ( intervals. get ( i) . start, Math . max ( intervals. get ( i+ 1 ) . end, intervals. get ( i) . end) ) ) ;
} else {
res. add ( intervals. get ( i) ) ;
}
}
res. add ( intervals. get ( intervals. size ( ) - 1 ) ) ;
return res;
}
}
NC 38 螺旋矩阵
示例1
输入:[[1,2,3],[4,5,6],[7,8,9]]
返回值:[1,2,3,6,9,8,7,4,5]
示例2
输入:[]
返回值:[]
思路:
模拟法:按圈打印
import java. util. ArrayList ;
public class Solution {
public ArrayList < Integer > spiralOrder ( int [ ] [ ] matrix) {
ArrayList < Integer > res= new ArrayList < Integer > ( ) ;
if ( matrix. length== 0 || matrix[ 0 ] . length== 0 ) return res;
int row= matrix. length, column= matrix[ 0 ] . length;
int x1= 0 , y1= 0 , x2= column- 1 , y2= row- 1 ;
while ( x1<= x2&& y1<= y2) {
for ( int i= x1; i<= x2; i++ ) {
res. add ( matrix[ y1] [ i] ) ;
}
for ( int i= y1+ 1 ; i<= y2; i++ ) {
res. add ( matrix[ i] [ x2] ) ;
}
if ( x1!= x2&& y1!= y2) {
for ( int i= x2- 1 ; i>= x1; i-- ) {
res. add ( matrix[ y2] [ i] ) ;
}
for ( int j= y2- 1 ; j>= y1+ 1 ; j-- ) {
res. add ( matrix[ j] [ x1] ) ;
}
}
x1++ ;
y1++ ;
x2-- ;
y2-- ;
}
return res;
}
}
NC41 最长无重复子数组
示例1
输入:[2,3,4,5]
返回值:4
说明:[2,3,4,5]是最长子数组
示例2
输入:[2,2,3,4,3]
返回值:3
说明:[2,3,4]是最长子数组
示例3
输入:[9]
返回值:1
示例4
输入:[1,2,3,1,2,3,2,2]
返回值:3
说明:最长子数组为[1,2,3]
思路1:
滑动窗口
时间复杂度:O(n)
空间复杂度:O(n)
import java. util. * ;
public class Solution {
public int maxLength ( int [ ] arr) {
if ( arr. length < 2 ) return arr. length;
HashMap < Integer , Integer > windows = new HashMap < > ( ) ;
int res = 0 ;
int left = - 1 ;
for ( int right = 0 ; right < arr. length; right++ ) {
if ( windows. containsKey ( arr[ right] ) ) {
left = Math . max ( left, windows. get ( arr[ right] ) ) ;
}
res = Math . max ( res, right- left) ;
windows. put ( arr[ right] , right) ;
}
return res;
}
}
NC46 加起来和为目标值的组合(二)
要求:空间复杂度 O(n!), 时间复杂度 O(n!)
示例1
输入:[100,10,20,70,60,10,50],80
返回值:[[10,10,60],[10,20,50],[10,70],[20,60]]
说明:给定的候选数集是[100,10,20,70,60,10,50],目标数是80
示例2
输入:[2],1
返回值:[]
import java. util. * ;
public class Solution {
public ArrayList < ArrayList < Integer > > combinationSum2 ( int [ ] num, int target) {
ArrayList < ArrayList < Integer > > res = new ArrayList < ArrayList < Integer > > ( ) ;
ArrayList < Integer > arr = new ArrayList < Integer > ( ) ;
if ( num == null || num. length== 0 || target< 0 ) return res;
Arrays . sort ( num) ;
dfs ( num, target, res, arr, 0 ) ;
return res;
}
void dfs ( int [ ] num, int target, ArrayList < ArrayList < Integer > > res, ArrayList < Integer > arr, int start) {
if ( target== 0 ) {
res. add ( new ArrayList < Integer > ( arr) ) ;
return ;
}
if ( start >= num. length) return ;
for ( int i= start; i< num. length; i++ ) {
if ( i > start && num[ i] == num[ i- 1 ] ) continue ;
if ( num[ i] <= target) {
arr. add ( num[ i] ) ;
dfs ( num, target- num[ i] , res, arr, i+ 1 ) ;
arr. remove ( arr. size ( ) - 1 ) ;
}
}
return ;
}
}
NC54 数组中相加和为0的三元组
空间复杂度:O(n^2,时间复杂度 O(n^2)
示例1
输入:[0]
返回值:[]
示例2
输入:[-2,0,1,1,2]
返回值:[[-2,0,2],[-2,1,1]]
示例3
输入:[-10,0,10,20,-10,-40]
返回值:[[-10,-10,20],[-10,0,10]]
思路:
for循环+左右指针
import java. util. * ;
public class Solution {
public ArrayList < ArrayList < Integer > > threeSum ( int [ ] num) {
ArrayList < ArrayList < Integer > > res= new ArrayList < ArrayList < Integer > > ( ) ;
if ( num. length< 3 ) return res;
Arrays . sort ( num) ;
for ( int i= 0 ; i< num. length- 2 ; i++ ) {
if ( i> 0 && num[ i] == num[ i- 1 ] ) continue ;
int left= i+ 1 , right= num. length- 1 ;
while ( left< right) {
if ( ( num[ i] + num[ left] + num[ right] ) == 0 ) {
ArrayList < Integer > temp= new ArrayList < > ( ) ;
temp. add ( num[ i] ) ;
temp. add ( num[ left] ) ;
temp. add ( num[ right] ) ;
res. add ( temp) ;
while ( left< right&& num[ left] == num[ ++ left] ) ;
while ( left< right&& num[ right] == num[ -- right] ) ;
} else if ( ( num[ i] + num[ left] + num[ right] ) > 0 ) {
right-- ;
} else {
left++ ;
}
}
}
return res;
}
}
NC59 矩阵的最小路径和
给定一个n*m 的矩阵 a,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,输出所有的路径中最小的路径和。
数据范围:0<n,m≤50,矩阵中任意值都满足0<ai,aj≤100
要求:空间复杂度O(1),时间复杂度O(nm)
示例1
输入:[[1,3,5,9],[8,1,3,4],[5,0,6,1],[8,8,4,0]]
返回值:12
示例2
输入:[[1,2,3],[1,2,3]]
返回值:7
思路1:(可以满足复杂度要求)
动态规划:dp[i][j]=matrix[i][j]+Math.min(dp[i-1][j],dp[i][j-1])
思路2:(超时)
递归:minPath(grid,grid.length-1,grid[0].length-1)=grid[i][j] + Math.min(minPathSum(grid,i-1,j), minPathSum(grid,i,j-1))
思路一:
import java. util. * ;
public class Solution {
public int minPathSum ( int [ ] [ ] grid) {
if ( grid. length== 0 || grid[ 0 ] . length== 0 ) return 0 ;
for ( int i= 0 ; i< grid. length; i++ ) {
for ( int j= 0 ; j< grid[ 0 ] . length; j++ ) {
if ( i== 0 && j== 0 ) {
continue ;
} else if ( i== 0 && j!= 0 ) {
grid[ i] [ j] = grid[ i] [ j] + grid[ i] [ j- 1 ] ;
} else if ( i!= 0 && j== 0 ) {
grid[ i] [ j] = grid[ i] [ j] + grid[ i- 1 ] [ j] ;
} else {
grid[ i] [ j] = grid[ i] [ j] + Math . min ( grid[ i] [ j- 1 ] , grid[ i- 1 ] [ j] ) ;
}
}
}
return grid[ grid. length- 1 ] [ grid[ 0 ] . length- 1 ] ;
}
}
思路二:超时
import java. util. * ;
public class Solution {
public int minPathSum ( int [ ] [ ] grid) {
return minPathSum ( grid, grid. length - 1 , grid[ 0 ] . length - 1 ) ;
}
public int minPathSum ( int [ ] [ ] grid, int i, int j) {
if ( i == 0 && j == 0 ) return grid[ i] [ j] ;
if ( i == 0 ) return grid[ i] [ j] + minPathSum ( grid, i, j - 1 ) ;
if ( j == 0 ) return grid[ i] [ j] + minPathSum ( grid, i - 1 , j) ;
return grid[ i] [ j] + Math . min ( minPathSum ( grid, i - 1 , j) , minPathSum ( grid, i, j - 1 ) ) ;
}
}
NC61 两数之和
描述
给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。(注:返回的数组下标从1开始算起)
数据范围:2≤len(numbers)≤1500,-10≤numbers≤10^9, 0≤target≤10^9
要求:空间复杂度 O(n),时间复杂度 O(nlogn)
例如:
给出的数组为 [20,70,110,150],目标值为90
返回一个数组 [1,2] ,因为numbers1+numbers 2=20+70=90
示例1
输入:[3,2,4],6
返回值:[2,3]
说明:因为 2+4=6 ,而 2的下标为2 , 4的下标为3 ,又因为 下标2 < 下标3 ,所以返回[2,3]
示例2
输入:[20,70,110,150],90
返回值:[1,2]
import java. util. * ;
public class Solution {
public int [ ] twoSum ( int [ ] numbers, int target) {
if ( numbers. length< 2 ) return null ;
HashMap < Integer , Integer > map= new HashMap < Integer , Integer > ( ) ;
for ( int i= 0 ; i< numbers. length; i++ ) {
if ( map. containsKey ( target- numbers[ i] ) ) {
return new int [ ] { map. get ( target- numbers[ i] ) , i+ 1 } ;
}
map. put ( numbers[ i] , i+ 1 ) ;
}
return null ;
}
}
NC65 斐波那契数列
描述
大家都知道斐波那契数列,现在要求输入一个正整数 n ,请你输出斐波那契数列的第 n 项。斐波那契数列是一个满足 fib ( x) = fib ( x−1 ) + fib ( x−2 ) 的数列
数据范围:1 ≤n≤39 要求:空间复杂度 O ( 1 ) ,时间复杂度 O ( n) ,本题也有时间复杂度 O ( logn) 的解法
输入描述:一个正整数n
返回值描述:输出一个正整数。
示例1
输入:4
返回值:3
说明:根据斐波那契数列的定义可知,fib ( 1 ) = 1 , fib ( 2 ) = 1 , fib ( 3 ) = fib ( 3 - 1 ) + fib ( 3 - 2 ) = 2 , fib ( 4 ) = fib ( 4 - 1 ) + fib ( 4 - 2 ) = 3 ,所以答案为4 。
示例2
输入:1
返回值:1
示例3
输入:2
返回值:1
思路1:
递归写法 空间复杂度O(1) 时间复杂度O(2^n)
思路2:
动态规划 空间复杂度O(n) 时间复杂度O(n)
思路3:
动态规划改进写法,运算当前值只需要两个数即可 时间复杂度O(n)
思路1 :
public class Solution {
public int Fibonacci ( int n) {
if ( n== 1 || n== 2 ) return 1 ;
return Fibonacci ( n- 1 ) + Fibonacci ( n- 2 ) ;
}
}
思路2 :
public class Solution {
public int Fibonacci ( int n) {
if ( n== 1 || n== 2 ) return 1 ;
int [ ] dp= new int [ n+ 1 ] ;
dp[ 1 ] = 1 ;
dp[ 2 ] = 1 ;
for ( int i= 3 ; i<= n; i++ ) {
dp[ i] = dp[ i- 1 ] + dp[ i- 2 ] ;
}
return dp[ n] ;
}
}
思路3 :
public class Solution {
public int Fibonacci ( int n) {
if ( n== 1 || n== 2 ) return 1 ;
int a= 1 , b= 1 , c= a+ b;
for ( int i= 3 ; i<= n; i++ ) {
c= a+ b;
a= b;
b= c;
}
return b;
}
}
NC73 数组中出现次数超过一半的数字
描述
给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
数据范围:0≤n≤50000,数组中元素的值0≤val≤10000
要求:空间复杂度:O(1),时间复杂度 O(n)
输入描述:保证数组输入非空,且保证有解
示例1
输入:[1,2,3,2,2,2,5,4,2]
返回值:2
示例2
输入:[3,3,3,3,2,2,2]
返回值:3
示例3
输入:[1]
返回值:1
思路1:
快速排序输出最中间的值 空间复杂度:O(1),时间复杂度 O(nlog(n))
思路2:
hashmap 空间复杂度:O(n),时间复杂度 O(n)
思路3:
候选法:
加入数组中存在众数,那么众数一定大于数组的长度的一半。
思想就是:如果两个数不相等,就消去这两个数,最坏情况下,每次消去一个众数和一个非众数,那么如果存在众数,最后留下的数肯定是众数
思路1 :
import java. util. * ;
public class Solution {
public int MoreThanHalfNum_Solution ( int [ ] array) {
Arrays . sort ( array) ;
return array[ array. length/ 2 ] ;
}
}
思路2 :
import java. util. * ;
public class Solution {
public int MoreThanHalfNum_Solution ( int [ ] array) {
HashMap < Integer , Integer > map= new HashMap < Integer , Integer > ( ) ;
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 ) ;
}
}
for ( Map. Entry < Integer , Integer > m: map. entrySet ( ) ) {
if ( m. getValue ( ) > array. length/ 2 ) return m. getKey ( ) ;
}
return 0 ;
}
}
思路3 :
import java. util. * ;
public class Solution {
public int MoreThanHalfNum_Solution ( int [ ] numbers) {
int condatate= numbers[ 0 ] ;
int count= 1 ;
for ( int i= 1 ; i< numbers. length; i++ ) {
if ( numbers[ i] == condatate) {
count++ ;
} else {
count-- ;
}
if ( count== 0 ) {
condatate= numbers[ i+ 1 ] ;
}
}
return condatate;
}
}
NC74 数字在升序数组中出现的次数
思路1:
遍历 空间复杂度:O(1),时间复杂度 O(n)
思路2:
二分查找 找到k之后 判断left和right是否是k 是的话变动指针,不是的话right--;
空间复杂度:O(1),时间复杂度 O(log(n))
思路1 :
public class Solution {
public int GetNumberOfK ( int [ ] array , int k) {
int count = 0 ;
for ( int e: array) {
if ( k== e) count++ ;
}
return count;
}
}
思路2 :
public class Solution {
public int GetNumberOfK ( int [ ] array , int k) {
int left= 0 ;
int right= array. length- 1 ;
int count= 0 ;
while ( left<= right&& left>= 0 && right<= array. length- 1 ) {
int mid= ( left+ right) / 2 ;
if ( array[ mid] > k) {
right= mid- 1 ;
} else if ( array[ mid] < k) {
left= mid+ 1 ;
} else {
if ( array[ left] == k) {
count+= ( mid- left+ 1 ) ;
left= mid+ 1 ;
} else if ( array[ right] == k) {
count+= ( right- mid+ 1 ) ;
right= mid- 1 ;
} else {
right-= 1 ;
}
}
}
return count;
}
}
NC77 调整数组顺序使奇数位于偶数前面(一)
描述
输入一个长度为 n 整数数组,数组里面不含有相同的元素,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前面部分,所有的偶数位于数组的后面部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
数据范围:0≤n≤5000,数组中每个数的值0≤val≤10000
要求:时间复杂度 O(n),空间复杂度 O(n)
进阶:时间复杂度 O(n^2),空间复杂度 O(1)
示例1
输入:[1,2,3,4]
返回值:[1,3,2,4]
示例2
输入:[2,4,6,5,7]
返回值:[5,7,2,4,6]
示例3
输入:[1,3,5,6,7]
返回值:[1,3,5,7,6]
思路1:
插入排序 空间复杂度:O(1),时间复杂度 O(n^2)
思路2:
重新new数组 空间复杂度:O(n),时间复杂度 O(n)
思路1 :
import java. util. * ;
public class Solution {
public int [ ] reOrderArray ( int [ ] array) {
for ( int i= 0 ; i< array. length; i++ ) {
if ( array[ i] % 2 == 1 ) {
int index= i;
while ( index> 0 && array[ index- 1 ] % 2 == 0 ) {
int temp= array[ index] ;
array[ index] = array[ index- 1 ] ;
array[ index- 1 ] = temp;
index-- ;
}
}
}
return array;
}
}
思路2 :
import java. util. * ;
public class Solution {
public int [ ] reOrderArray ( int [ ] array) {
if ( array. length <= 1 ) {
return array;
}
int [ ] res = new int [ array. length] ;
int index = 0 ;
for ( int i = 0 ; i < array. length; i ++ ) {
if ( ( array[ i] & 1 ) == 1 ) {
res[ index ++ ] = array[ i] ;
}
}
for ( int i = 0 ; i < array. length; i ++ ) {
if ( ( array[ i] & 1 ) == 0 ) {
res[ index ++ ] = array[ i] ;
}
}
return res;
}
}
NC83 子数组最大乘积
描述
给定一个double类型的数组arr,其中的元素可正可负可0,返回连续子数组累乘的最大乘积。
数据范围:数组大小满足0≤n≤10,数组中元素满足∣val∣≤10
进阶:空间复杂度 O(1),时间复杂度 O(n)
示例1
输入:[-2.5,4,0,3,0.5,8,-1]
返回值:12.00000
说明:取连续子数组[3,0.5,8]可得累乘的最大乘积为12.00000
示例2
输入:[1.0,0.0,0.0]
返回值:1.00000
说明:取连续子数组[1.0]可得累乘的最大乘积为1.00000
思路:
动态规划:
max[i]=Math.max(num[i],num[i]*max[i-1],num[i]*min[i-1])
min[i]=Math.min(num[i],num[i]*max[i-1],num[i]*min[i-1])
public class Solution {
public double maxProduct ( double [ ] nums) {
double max = nums[ 0 ] , min = nums[ 0 ] ;
double res = nums[ 0 ] ;
for ( int i = 1 ; i < nums. length; ++ i) {
double m = max, n = min;
max = Math . max ( nums[ i] , Math . max ( nums[ i] * m, nums[ i] * n) ) ;
min = Math . min ( nums[ i] , Math . min ( nums[ i] * m, nums[ i] * n) ) ;
res = Math . max ( res, max) ;
}
return res;
}
}
NC95 数组中的最长连续子序列
描述
给定无序数组arr,返回其中最长的连续序列的长度(要求值连续,位置可以不连续,例如 3,4,5,6为连续的自然数)
数据范围:1≤n≤10^5,数组中的值满足1≤val≤10^8
要求:空间复杂度 O(n),时间复杂度 O(nlogn)
示例1
输入:[100,4,200,1,3,2]
返回值:4
解释:1、2、3、4
示例2
输入:[1,1,1]
返回值:1
思路1:
快速排序,在寻找连续的长度 空间复杂度 O(1),时间复杂度 O(nlogn)
import java. util. * ;
public class Solution {
public int MLS ( int [ ] arr) {
if ( arr == null || arr. length== 0 ) return - 1 ;
Arrays . sort ( arr) ;
int maxLen= 1 ;
int count= 1 ;
for ( int i= 1 ; i< arr. length; i++ ) {
if ( arr[ i] == arr[ i- 1 ] ) continue ;
if ( arr[ i] - arr[ i- 1 ] == 1 ) {
count++ ;
} else {
count= 1 ;
}
maxLen= Math . max ( maxLen, count) ;
}
return maxLen;
}
}
NC106 三个数的最大乘积
描述
给定一个长度为 n 的无序数组 A ,包含正数、负数和 0 ,请从中找出3个数,使得乘积最大,返回这个乘积。
要求时间复杂度:O(n) ,空间复杂度:O(1)
数据范围:3≤n≤10^4,-10^4≤A[i]≤10^4
示例1
输入:[3,4,1,2]
返回值:24
思路:三种情况:
1 全是正数 :最大的三个数
2 全是负数 : 最大的三个数
3 一半正数 一半负数 : Math.max(最大的三个数9,最小的两个数*最大的数)
时间复杂度:O(n) ,空间复杂度:O(1)
思路1 :
import java. util. * ;
public class Solution {
public long solve ( int [ ] A ) {
int max1= Integer . MIN_VALUE, max2= Integer . MIN_VALUE, max3= Integer . MIN_VALUE;
int min1 = Integer . MAX_VALUE, min2 = Integer . MAX_VALUE;
for ( int num: A ) {
if ( num > max1) {
max3 = max2;
max2 = max1;
max1 = num;
} else if ( num > max2) {
max3 = max2;
max2 = num;
} else if ( num > max3) {
max3 = num;
}
if ( num < min1) {
min2 = min1;
min1 = num;
} else if ( num < min2) {
min2 = num;
}
}
return Math . max ( ( long ) max1* max2* max3, ( long ) max1* min1* min2) ;
}
}
NC107 寻找峰值
描述
给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个所在位置即可。
1.峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于
2.假设nums[-1]=nums[n]=−∞
3.对于所有有效的 i 都有 nums[i] != nums[i + 1]
4.你可以使用O(logN)的时间复杂度实现此问题吗?
示例1
输入:[2,4,1,2,7,8,4]
返回值:1
说明:4和8都是峰值元素,返回4的索引1或者8的索引5都可以
示例2
输入:[1,2,3,1]
返回值:2
说明:3 是峰值元素,返回其索引 2
思路1:
寻找大于左右元素的索引 时间复杂度:O(n),空间复杂度:O(1)
思路2:
关键思想:下坡的时候可能找到波峰,但是可能找不到,一直向下走的 时间复杂度:O(log(n)),空间复杂度:O(1)
上坡的时候一定能找到波峰,因为题目给出的是nums[-1] = nums[n] = -∞
思路1 :
import java. util. * ;
public class Solution {
public int findPeakElement ( int [ ] nums) {
for ( int i= 1 ; i< nums. length- 1 ; i++ ) {
if ( nums[ i] > nums[ i- 1 ] && nums[ i] > nums[ i+ 1 ] ) return i;
}
return nums[ nums. length- 1 ] > nums[ 0 ] ? nums. length- 1 : 0 ;
}
}
思路2 :
import java. util. * ;
public class Solution {
public int findPeakElement ( int [ ] nums) {
int left= 0 , right= nums. length- 1 ;
while ( left< right) {
int mid= left+ ( right- left) / 2 ;
if ( nums[ mid] > nums[ mid+ 1 ] ) {
right= mid;
} else {
left= mid+ 1 ;
}
}
return right;
}
}