位运算
异或
一个数组中只有一个数出现了奇数次,其他都出现了偶数次。以最快的速度找到这个出现计数次的数。 利用数字异或。
public static void main ( String [ ] args) {
List < Integer > list = Arrays . asList ( 7 , 4 , 7 , 7 , 4 , 5 , 6 , 5 , 6 , 88 , 99 , 99 , 88 ) ;
System . out. println ( getNumber ( list) ) ;
}
private static int getNumber ( List < Integer > list) {
int result = 0 ;
for ( Integer number: list) {
result = result^ number;
}
return result;
}
两个数做交换不申请额外的空间
public static void main ( String [ ] args) {
int first = 4 ;
int second = 8 ;
System . out. println ( "first:" + first) ;
System . out. println ( "second:" + second) ;
replaceNumber ( first, second) ;
}
private static void replaceNumber ( int first, int second) {
first = first^ second;
second = first^ second;
first = first^ second;
System . out. println ( "first:" + first) ;
System . out. println ( "seconde:" + second) ;
}
提取二进制数最右侧的1
public static void main ( String [ ] args) {
int a = 5 ;
System . out. println ( a& ( ~ a+ 1 ) ) ;
int b = 5 ;
System . out. println ( b& ( - b) ) ;
}
一个数组中只有两个数a和b出现了奇数次,其他都出现了偶数次。以最快的速度找到这个出现奇数次的数。
同1.获得一个中间数middle(a&b) 同3.获取middle最右侧1的位置(a≠b),根据这个1的位置将数组分为两部分,一部分包含a,一部分包含b 将第一部分按照1.操作,获得a或者b
public static void main ( String [ ] args) {
List < Integer > array = Arrays . asList ( 7 , 11 , 7 , 11 , 23 , 23 , 56 , 56 , 7 , 89 , 9 , 89 , 9 , 67 , 67 , 9 ) ;
getNumber ( array) ;
}
private static void getNumber ( List < Integer > array) {
int middle = 0 ;
for ( int number : array) {
middle ^= number;
}
int rightOne = middle & ( - middle) ;
int leftNumber = 0 ;
for ( int number : array) {
if ( ( number & rightOne) == 0 ) {
leftNumber ^= number;
}
}
System . out. println ( leftNumber) ;
System . out. println ( leftNumber ^ middle) ;
}
二分有序数组
查找某个数
找到一个数
private static Integer findNumberLow ( List < Integer > array, Integer number) {
int maxIndex = array. size ( ) - 1 ;
int middleIndex = maxIndex / 2 ;
int minIndex = 0 ;
Integer middle;
while ( ! ( middle = array. get ( middleIndex) ) . equals ( number) ) {
if ( ( minIndex == middleIndex || maxIndex == middleIndex) ) {
return - 1 ;
}
if ( middle > number) {
maxIndex = middleIndex;
middleIndex = ( ( maxIndex - minIndex) / 2 + minIndex) ;
}
if ( middle < number) {
minIndex = middleIndex;
middleIndex = ( maxIndex - ( maxIndex - minIndex) / 2 ) ;
}
}
return middleIndex;
}
private static Integer findNumber ( List < Integer > array, Integer number) {
int maxIndex = array. size ( ) - 1 ;
int minIndex = 0 ;
int middleIndex;
while ( minIndex <= maxIndex) {
middleIndex = minIndex + ( ( maxIndex - minIndex) >> 1 ) ;
Integer middle = array. get ( middleIndex) ;
if ( middle > number) {
maxIndex = middleIndex - 1 ;
} else if ( middle < number) {
minIndex = middleIndex + 1 ;
} else {
return middleIndex;
}
}
return - 1 ;
}
找到大于一个数最左的位置
private static Integer findGreatLeft ( List < Integer > array, Integer number) {
int maxIndex = array. size ( ) - 1 ;
int middleIndex;
int minIndex = 0 ;
int greatLeft = - 1 ;
while ( minIndex <= maxIndex) {
middleIndex = minIndex + ( ( maxIndex - minIndex) >> 1 ) ;
Integer middle = array. get ( middleIndex) ;
if ( middle >= number) {
greatLeft = middleIndex;
maxIndex = middleIndex - 1 ;
} else {
minIndex = middleIndex + 1 ;
}
}
return greatLeft;
}
找到小于一个数最右的位置
private static Integer findLessRight ( List < Integer > array, Integer number) {
int maxIndex = array. size ( ) - 1 ;
int middleIndex;
int minIndex = 0 ;
int greatLeft = - 1 ;
while ( minIndex <= maxIndex) {
middleIndex = minIndex + ( ( maxIndex - minIndex) >> 1 ) ;
Integer middle = array. get ( middleIndex) ;
if ( middle > number) {
maxIndex = middleIndex - 1 ;
} else {
greatLeft = middleIndex;
minIndex = middleIndex + 1 ;
}
}
return greatLeft;
}
assert
private static void assertTrue ( ) {
Random random = new Random ( ) ;
for ( int times= 0 ; times< 10000 ; times++ ) {
List < Integer > array = new ArrayList < > ( ) ;
for ( int i= 0 ; i< 100 ; i++ ) {
array. add ( random. nextInt ( 1000 ) ) ;
}
array = array. stream ( ) . sorted ( ) . distinct ( ) . collect ( Collectors . toList ( ) ) ;
int number = random. nextInt ( 1000 ) ;
Assert . isTrue ( findNumberForeach ( array, number) . equals ( findNumber ( array, number) ) ,
"findNumberForeach(array,number).equals(findNumber(array,number))" + array+ ";" + number) ;
Assert . isTrue ( findNumberForeach ( array, number) . equals ( findNumberLow ( array, number) ) ,
"findNumberForeach(array,number).equals(findNumberLow(array,number))" + array+ ";" + number) ;
Assert . isTrue ( findGreatLeftForeach ( array, number) . equals ( findGreatLeft ( array, number) ) ,
"findGreatLeftForeach(array,number).equals(findGreatLeft(array,number))" + array+ ";" + number) ;
Assert . isTrue ( findLessRightForeach ( array, number) . equals ( findLessRight ( array, number) ) ,
"findLessRightForeach(array,number).equals(findLessRight(array,number))" + array+ ";" + number) ;
}
}
二分答案
定义一种算法数字和:例如:345:345+34+3=382,则384为345的数字和,345为384的种子数。给定一个数n求他的种子
@Test
public void testNumberSum ( ) {
Assert . isTrue ( numberSumRecursion ( 345 ) == 382 ) ;
Assert . isTrue ( getSeed ( 382 ) == 345 ) ;
}
public int getSeed ( int number) {
int max = number;
int min = 0 ;
int seed;
int sum = - 1 ;
while ( true ) {
seed = ( min + ( ( max - min) >> 1 ) ) ;
sum = numberSumRecursion ( seed) ;
if ( sum > number) {
max = seed - 1 ;
}
if ( sum < number) {
min = seed + 1 ;
}
if ( sum == number) {
break ;
}
}
return seed;
}
public int numberSumRecursion ( int number) {
int i = number / 10 ;
if ( i > 0 ) {
return number + numberSumRecursion ( i) ;
} else {
return number;
}
}
猴子喜欢吃香蕉,这里有n堆香蕉,i堆香蕉的个数为arr[i],猴子以一定的速度k吃香蕉,每小时只吃一次。管理员离开h小时,猴子以最慢的速度吃完,最慢速度为多少。
public int minEatingSpeed ( int [ ] piles, int h) {
int maxSpeed = getMaxSpeed ( piles) ;
int minSpeed = 1 ;
int middleSpeed = - 1 ;
long resultHour;
int resultSpeed = - 1 ;
while ( minSpeed <= maxSpeed) {
middleSpeed = ( minSpeed + ( ( maxSpeed - minSpeed) >> 1 ) ) ;
resultHour = getEatH ( piles, middleSpeed) ;
if ( resultHour > h) {
minSpeed = middleSpeed + 1 ;
} else {
maxSpeed = middleSpeed - 1 ;
resultSpeed= middleSpeed;
}
}
return resultSpeed;
}
private long getEatH ( int [ ] arr, int k) {
long resultHour = 0 ;
for ( int i : arr) {
resultHour += ( i + k - 1 ) / k;
}
return resultHour;
}
private int getMaxSpeed ( int [ ] arr) {
int result = - 1 ;
for ( int i : arr) {
if ( i > result) {
result = i;
}
}
return result;
}
画家画画,加油桶 需要处理的画作arr[],画家人数k,最短时间完成
public int splitArray ( int [ ] nums, int k) {
long result = Long . MAX_VALUE;
long maxTime = getMaxTime ( nums) ;
long minTime = 0 ;
while ( minTime <= maxTime) {
long middleTime = ( minTime + ( ( maxTime - minTime) >> 1 ) ) ;
long completeK = getCompleteK ( nums, middleTime) ;
if ( completeK > k) {
minTime = middleTime + 1 ;
} else if ( completeK <= k) {
maxTime = middleTime - 1 ;
result = middleTime;
}
}
return ( int ) result;
}
private long getCompleteK ( int [ ] arr, long time) {
long resultK = 1 ;
long everyTime = time;
for ( int i : arr) {
if ( time < i) {
return Long . MAX_VALUE;
}
everyTime -= i;
if ( everyTime < 0 ) {
everyTime = time - i;
resultK += 1 ;
}
}
return resultK;
}
private long getMaxTime ( int [ ] arr) {
long result = 0 ;
for ( int i : arr) {
result += i;
}
return result;
}