概述
连续存储空间,存相同类型数据的集合 二维数组内存空间
二分查找
前提:数组元素有序 且不重复 时间复杂度:O(logn) 注意
left与right边界取值情况
分析 暴力解法
时间复杂度:O ( n)
-- -- -- -- -- -- -- -- -- -- -- --
class Solution {
public int searchInsert ( int [ ] nums, int target) {
for ( int i= 0 ; i< nums. length; i++ ) {
if ( nums[ i] >= target) {
return i;
}
}
return nums. length;
}
}
class Solution {
public int searchInsert ( int [ ] nums, int target) {
int left= 0 ;
int rigth = nums. length- 1 ;
int temp = nums. length;
while ( left<= rigth) {
int mid = ( left+ rigth) >>> 1 ;
if ( nums[ mid] >= target) {
temp = mid;
rigth = mid- 1 ;
} else {
left = mid+ 1 ;
}
}
return temp;
}
}
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
class Solution {
public int searchInsert ( int [ ] nums, int target) {
int left = 0 ;
int right = nums. length- 1 ;
int mid = 0 ;
while ( left<= right) {
mid = ( left+ right) >>> 1 ;
if ( target> nums[ mid] ) {
left= mid+ 1 ;
} else if ( target< nums[ mid] ) {
right= mid- 1 ;
} else {
return mid;
}
}
return right+ 1 ;
}
}
class Solution {
public int [ ] searchRange ( int [ ] nums, int target) {
if ( nums. length<= 0 ) return new int [ ] { - 1 , - 1 } ;
int start = - 1 ;
for ( int i= 0 ; i< nums. length; i++ ) {
if ( nums[ i] == target) {
start= i;
break ;
}
}
if ( start== - 1 ) return new int [ ] { - 1 , - 1 } ;
for ( int i= start; i<= nums. length; i++ ) {
if ( i== nums. length || nums[ i] != target) {
return new int [ ] { start, i- 1 } ;
}
}
return new int [ ] { - 1 , - 1 } ;
}
}
class Solution {
public int [ ] searchRange ( int [ ] nums, int target) {
int left= searchLeft ( nums, target) ;
int right= searchRight ( nums, target) ;
return new int [ ] { left, right} ;
}
public int searchLeft ( int [ ] nums, int target) {
int left= 0 ;
int right= nums. length- 1 ;
while ( left<= right) {
int mid= left+ ( right- left) / 2 ;
if ( nums[ mid] == target) {
if ( mid== 0 || nums[ mid- 1 ] != target) {
return mid;
}
right = mid- 1 ;
} else if ( nums[ mid] > target) {
right = mid - 1 ;
} else {
left = mid + 1 ;
}
}
return - 1 ;
}
public int searchRight ( int [ ] nums, int target) {
int left= 0 ;
int right= nums. length- 1 ;
while ( left<= right) {
int mid= left+ ( right- left) / 2 ;
if ( nums[ mid] == target) {
if ( mid== nums. length- 1 || nums[ mid+ 1 ] != target) {
return mid;
}
left = mid+ 1 ;
} else if ( nums[ mid] > target) {
right = mid - 1 ;
} else {
left = mid + 1 ;
}
}
return - 1 ;
}
}
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
class Solution {
public int [ ] searchRange ( int [ ] nums, int target) {
int leftOrder= searchLeft ( nums, target) ;
int rightOrder= searchRight ( nums, target) ;
if ( leftOrder== - 2 || rightOrder== - 2 ) return new int [ ] { - 1 , - 1 } ;
if ( rightOrder- leftOrder> 1 ) return new int [ ] { leftOrder+ 1 , rightOrder- 1 } ;
return new int [ ] { - 1 , - 1 } ;
}
public int searchLeft ( int [ ] nums, int target) {
int left= 0 ;
int right= nums. length- 1 ;
int temp = - 2 ;
while ( left<= right) {
int mid= left+ ( right- left) / 2 ;
if ( nums[ mid] >= target) {
right = mid - 1 ;
temp = right;
} else {
left = mid + 1 ;
}
}
return temp;
}
public int searchRight ( int [ ] nums, int target) {
int left= 0 ;
int right= nums. length- 1 ;
int temp = - 2 ;
while ( left<= right) {
int mid= left+ ( right- left) / 2 ;
if ( nums[ mid] > target) {
right = mid- 1 ;
} else {
left = mid + 1 ;
temp = left;
}
}
return temp;
}
}
袖珍计算器算法
利用指数函数与对数函数代替平方根函数
时间复杂度:O ( 1 )
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
class Solution {
public int mySqrt ( int x) {
int result = ( int ) Math . exp ( 0.5 * Math . log ( x) ) ;
return ( result+ 1 ) * ( result+ 1 ) == x? result+ 1 : result;
}
}
问题转换:根ans满足mid* mid<= x, 所以对k进行二分查找[ 0 , x] , 每一步比较mid* mid与x的值
时间复杂度:O ( logx)
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
class Solution {
public int mySqrt ( int x) {
int left = 0 , right = x, result= - 1 ;
while ( left<= right) {
int mid = left+ ( right- left) / 2 ;
if ( ( long ) mid* mid<= x) {
result= mid;
left= mid+ 1 ;
} else {
right= mid- 1 ;
}
}
return result;
}
}
牛顿迭代
class Solution {
public int mySqrt ( int x) {
if ( x== 0 ) return 0 ;
double x0 = x;
while ( true ) {
double result = 0.5 * ( x0+ x/ x0) ;
if ( Math . abs ( x0 - result) < 1e-7 ) {
return ( int ) result;
}
x0= result;
}
}
}
class Solution {
public boolean isPerfectSquare ( int num) {
int left = 0 ;
int right = num;
int result = - 1 ;
while ( left<= right) {
int mid = left+ ( right- left) / 2 ;
if ( ( long ) mid* mid<= num) {
result = mid;
left = mid + 1 ;
} else {
right = mid - 1 ;
}
}
return result* result== num? true : false ;
}
}
移除元素
可能是二分法做太多的原因,做啥都像二分法
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
class Solution {
public int removeElement ( int [ ] nums, int val) {
Arrays . sort ( nums) ;
int leftOrder = searchLeftOrder ( nums, val) ;
int rightOrder = searchRightOrder ( nums, val) ;
if ( leftOrder== - 2 || rightOrder== - 2 ) return nums. length;
int vals = rightOrder- leftOrder- 1 ;
if ( rightOrder!= nums. length) {
for ( int i= rightOrder; i< nums. length; i++ ) {
nums[ ++ leftOrder] = nums[ i] ;
}
}
return nums. length- vals;
}
public static int searchLeftOrder ( int [ ] nums, int val) {
int left = 0 ;
int right = nums. length- 1 ;
int leftOrder = - 2 ;
while ( left<= right) {
int mid = left+ ( right- left) / 2 ;
if ( nums[ mid] >= val) {
right = mid- 1 ;
leftOrder= right;
} else {
left = mid+ 1 ;
}
}
return leftOrder;
}
public static int searchRightOrder ( int [ ] nums, int val) {
int left = 0 ;
int right = nums. length- 1 ;
int rightOrder = - 2 ;
while ( left<= right) {
int mid = left+ ( right- left) / 2 ;
if ( nums[ mid] > val) {
right = mid- 1 ;
} else {
left = mid+ 1 ;
rightOrder= left;
}
}
return rightOrder;
}
}
class Solution {
public int removeElement ( int [ ] nums, int val) {
int left= 0 ;
for ( int i= 0 ; i< nums. length; i++ ) {
if ( nums[ i] != val) {
nums[ left] = nums[ i] ;
left++ ;
}
}
return left;
}
}
class Solution {
public int removeElement ( int [ ] nums, int val) {
int left= 0 ;
int right = nums. length;
while ( left< right) {
if ( nums[ left] == val) {
nums[ left] = nums[ -- right] ;
} else {
left++ ;
}
}
return left;
}
}
class Solution {
public int removeDuplicates ( int [ ] nums) {
int left = 0 ;
for ( int i= 1 ; i< nums. length; i++ ) {
if ( nums[ left] != nums[ i] ) {
left++ ;
nums[ left] = nums[ i] ;
}
}
return left+ 1 ;
}
}
class Solution {
public void moveZeroes ( int [ ] nums) {
int left= 0 ;
for ( int i= 0 ; i< nums. length; i++ ) {
if ( nums[ i] != 0 ) {
nums[ left] = nums[ i] ;
left++ ;
}
}
for ( int i= left; i< nums. length; i++ ) {
nums[ i] = 0 ;
}
}
}
class Solution {
public boolean backspaceCompare ( String s, String t) {
if ( s. equals ( t) ) return true ;
String s1 = backspaceNew ( s) ;
String t1 = backspaceNew ( t) ;
return s1. equals ( t1) ;
}
public static String backspaceNew ( String str) {
int start= 0 ;
StringBuffer sb = new StringBuffer ( str) ;
while ( start< sb. length ( ) ) {
int index = sb. indexOf ( "#" , start) ;
if ( index== - 1 ) {
break ;
}
if ( index== 0 ) {
sb. deleteCharAt ( index) ;
start= index;
continue ;
}
sb. delete ( index- 1 , index+ 1 ) ;
start= index- 1 ;
}
return sb. toString ( ) ;
}
}
class Solution {
public boolean backspaceCompare ( String s, String t) {
return backspaceStr ( s) . equals ( backspaceStr ( t) ) ;
}
public static String backspaceStr ( String str) {
int i= 0 , j= 0 ;
char [ ] ch = str. toCharArray ( ) ;
while ( i< ch. length) {
if ( ch[ i] != '#' ) {
ch[ j] = ch[ i] ;
j++ ;
} else if ( j!= 0 ) {
j-- ;
}
i++ ;
}
String res = "" ;
for ( i= 0 ; i< j; i++ ) {
res+= ch[ i] ;
}
return res;
}
}
class Solution {
public int [ ] sortedSquares ( int [ ] nums) {
for ( int i= 0 ; i< nums. length; i++ ) {
nums[ i] = nums[ i] * nums[ i] ;
}
Arrays . sort ( nums) ;
return nums;
}
}
class Solution {
public int [ ] sortedSquares ( int [ ] nums) {
int left = 0 ;
int rigth = nums. length- 1 ;
int [ ] numsNew = new int [ nums. length] ;
int index = nums. length- 1 ;
while ( left<= rigth) {
if ( Math . abs ( nums[ left] ) <= Math . abs ( nums[ rigth] ) ) {
numsNew[ index] = nums[ rigth] * nums[ rigth] ;
rigth-- ;
} else {
numsNew[ index] = nums[ left] * nums[ left] ;
left++ ;
}
index-- ;
}
return numsNew;
}
}
长度最小的子数组
class Solution {
public int minSubArrayLen ( int target, int [ ] nums) {
int min= nums. length* 2 ;
int sum= 0 ;
for ( int i= 0 ; i< nums. length; i++ ) {
for ( int j= i; j< nums. length; j++ ) {
sum+= nums[ j] ;
if ( sum>= target) {
min= Math . min ( min, j- i+ 1 ) ;
break ;
}
}
sum= 0 ;
}
return min== nums. length* 2 ? 0 : min;
}
}
class Solution {
public int minSubArrayLen ( int target, int [ ] nums) {
int start= 0 , end= 0 ;
int min = nums. length* 2 ;
int sum = 0 ;
while ( end< nums. length) {
sum += nums[ end] ;
while ( sum>= target) {
min= Math . min ( end- start+ 1 , min) ;
sum -= nums[ start++ ] ;
}
end++ ;
}
return min== nums. length* 2 ? 0 : min;
}
}
class Solution {
public int totalFruit ( int [ ] fruits) {
int type1 = - 1 ;
int type2 = - 1 ;
int left= 0 , rigth= 0 ;
int length = fruits. length;
int max = - 1 ;
int index= - 1 ;
while ( rigth<= length) {
if ( rigth== length) { max = Math . max ( max, rigth- left) ; break ; }
if ( type1== - 1 ) { type1= fruits[ rigth] ; }
if ( type2== - 1 && fruits[ rigth] != type1) {
type2= fruits[ rigth] ;
index= rigth;
}
if ( fruits[ rigth] != type1 && fruits[ rigth] != type2) {
max = Math . max ( max, rigth- left) ;
left= index;
rigth= index;
type1= - 1 ;
type2= - 1 ;
break ;
}
rigth++ ;
}
return max;
}
}
class Solution {
public int totalFruit ( int [ ] fruits) {
if ( fruits== null || fruits. length== 0 ) return 0 ;
int length = fruits. length;
int max = - 1 , left = 0 ;
Map < Integer , Integer > map = new HashMap < > ( ) ;
for ( int i= 0 ; i< length; i++ ) {
if ( map. get ( fruits[ i] ) == null ) {
map. put ( fruits[ i] , 1 ) ;
} else {
map. put ( fruits[ i] , map. get ( fruits[ i] ) + 1 ) ;
}
while ( map. size ( ) > 2 ) {
map. put ( fruits[ left] , map. get ( fruits[ left] ) - 1 ) ;
if ( map. get ( fruits[ left] ) == 0 ) map. remove ( fruits[ left] ) ;
left++ ;
}
max = Math . max ( max, i- left+ 1 ) ;
}
return max;
}
}
class Solution {
public String minWindow ( String s, String t) {
HashMap < Character , Integer > maps = new HashMap < Character , Integer > ( ) ;
HashMap < Character , Integer > mapt = new HashMap < Character , Integer > ( ) ;
for ( int i= 0 ; i< t. length ( ) ; i++ ) {
mapt. put ( t. charAt ( i) , mapt. getOrDefault ( t. charAt ( i) , 0 ) + 1 ) ;
}
String res = "" ;
int count = 0 ;
int minLen = Integer . MAX_VALUE;
for ( int i= 0 , j= 0 ; i< s. length ( ) ; i++ ) {
maps. put ( s. charAt ( i) , maps. getOrDefault ( s. charAt ( i) , 0 ) + 1 ) ;
if ( mapt. containsKey ( s. charAt ( i) ) && maps. get ( s. charAt ( i) ) <= mapt. get ( s. charAt ( i) ) ) {
count++ ;
}
while ( j< i && ( ! mapt. containsKey ( s. charAt ( j) ) || maps. get ( s. charAt ( j) ) > mapt. get ( s. charAt ( j) ) ) ) {
int num = maps. get ( s. charAt ( j) ) - 1 ;
maps. put ( s. charAt ( j) , num) ;
j++ ;
}
if ( count== t. length ( ) && i- j+ 1 < minLen) {
minLen= i- j+ 1 ;
res= s. substring ( j, i+ 1 ) ;
}
}
return res;
}
}
螺旋矩阵
模拟旋转过程
class Solution {
public int [ ] [ ] generateMatrix ( int n) {
int [ ] [ ] matrix = new int [ n] [ n] ;
int l= 0 , r= n- 1 , t= 0 , b= n- 1 ;
int num = 1 ;
while ( num<= n* n) {
for ( int i= l; i<= r; i++ ) matrix[ t] [ i] = num++ ;
t++ ;
for ( int i= t; i<= b; i++ ) matrix[ i] [ r] = num++ ;
r-- ;
for ( int i= r; i>= l; i-- ) matrix[ b] [ i] = num++ ;
b-- ;
for ( int i= b; i>= t; i-- ) matrix[ i] [ l] = num++ ;
l++ ;
}
return matrix;
}
}
上一题的逆过程, 但注意数组边界与循环退出时机
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
class Solution {
public List < Integer > spiralOrder ( int [ ] [ ] matrix) {
List < Integer > list = new ArrayList < Integer > ( ) ;
int n = matrix. length;
int m = matrix[ 0 ] . length;
int length = n* m;
int l= 0 , r= m, t= 0 , b= n;
while ( list. size ( ) < length) {
for ( int i= l; i< r; i++ ) list. add ( matrix[ t] [ i] ) ;
t++ ;
if ( t== b) break ;
for ( int i= t; i< b; i++ ) list. add ( matrix[ i] [ r- 1 ] ) ;
r-- ;
if ( r== l) break ;
for ( int i= r- 1 ; i>= l; i-- ) list. add ( matrix[ b- 1 ] [ i] ) ;
b-- ;
for ( int i= b- 1 ; i>= t; i-- ) list. add ( matrix[ i] [ l] ) ;
l++ ;
}
return list;
}
}
注意边界!!!!!
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
class Solution {
public int [ ] spiralOrder ( int [ ] [ ] matrix) {
int n = matrix. length;
if ( n== 0 ) { return new int [ 0 ] ; }
int m = matrix[ 0 ] . length;
int length = n* m;
int num= 0 ;
int [ ] array = new int [ length] ;
int l= 0 , r= m, t= 0 , b= n;
while ( num< length) {
for ( int i= l; i< r; i++ ) array[ num++ ] = matrix[ t] [ i] ;
t++ ;
if ( t== b) break ;
for ( int i= t; i< b; i++ ) array[ num++ ] = matrix[ i] [ r- 1 ] ;
r-- ;
if ( r== l) break ;
for ( int i= r- 1 ; i>= l; i-- ) array[ num++ ] = matrix[ b- 1 ] [ i] ;
b-- ;
if ( t== b) break ;
for ( int i= b- 1 ; i>= t; i-- ) array[ num++ ] = matrix[ i] [ l] ;
l++ ;
if ( r== l) break ;
}
return array;
}
}
总结
1.二分法
2.双指针法
通过快指针和慢指针在一个for循环下完成两个for循环的工作 可以改变原数组顺序使用首尾双指针
3.滑动窗口
相当于首尾双指针,但又不完全是 两层while循环,外层改变尾指针(窗口中的元素不满足要求),内层改变首指针(窗口中的元素满足要求,直到不满足要求时跳出到外层循环)
4.模拟行为
模拟事件发生的过程 不涉及算法,考察对代码的掌控能力