81. 求1+2!+3!+…+20!的和 ?
public class lianxi21 {
public static void main(String[] args) {
long sum = 0;
long fac = 1;
for(int i=1; i<=20; i++) {
fac = fac * i;
sum += fac;
}
System.out.println(sum);
}
}
82. 简述利用递归方法求5! ?
public class lianxi22 {
public static void main(String[] args) {
int n = 5;
rec fr = new rec();
System.out.println(n+”! = “+fr.rec(n));
}
}
class rec{
public long rec(int n) {
long value = 0 ;
if(n ==1 ) {
value = 1;
} else {
value = n * rec(n-1);
}
return value;
}
}
83. 有5个人坐在一起,问第五个人多少岁?
有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。问第2个人,说比第一个人大两岁。最后问第一个人,他说是10岁。请问第五个人多大?
public class lianxi23 {
public static void main(String[] args) {
int age = 10;
for(int i=2; i<=5; i++) {
age =age+2;
}
System.out.println(age);
}
}
84. 简述给一个不多于5位的正整数,要求:一、求它是几位数,二、逆序打印出各位数字。 ?
//使用了长整型最多输入18位
import java.util.*;
public class lianxi24 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.print(“请输入一个正整数:”);
long a = s.nextLong();
String ss = Long.toString(a);
char[] ch = ss.toCharArray();
int j=ch.length;
System.out.println(a + “是一个”+ j +”位数。”);
System.out.print(“按逆序输出是:”);
for(int i=j-1; i>=0; i–) {
System.out.print(ch[i]);
}
}
}
85. 简述一个5位数,判断它是不是回文数。即12321是回文数,个位与万位相同,十位与千位相同 ?
import java.util.;
public class lianxi25 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int a;
do{
System.out.print(“请输入一个5位正整数:”);
a = s.nextInt();
}while(a<10000||a>99999);
String ss =String.valueOf(a);
char[] ch = ss.toCharArray();
if(ch[0]==ch[4]&&ch[1]==ch[3]){
System.out.println(“这是一个回文数”);}
else {System.out.println(“这不是一个回文数”);}
}
}
//这个更好,不限位数
import java.util.;
public class lianxi25a {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
boolean is =true;
System.out.print(“请输入一个正整数:”);
long a = s.nextLong();
String ss = Long.toString(a);
char[] ch = ss.toCharArray();
int j=ch.length;
for(int i=0; i if(ch[i]!=ch[j-i-1]){is=false;}
}
if(is==true){System.out.println(“这是一个回文数”);}
else {System.out.println(“这不是一个回文数”);}
}
}
86. 请输入星期几的第一个字母来判断一下是星期几,如果第一个字母一样,则继续 判断第二个字母 ?
import java.util.*;
public class lianxi26 {
public static void main(String[] args) {
getChar tw = new getChar();
System.out.println(“请输入星期的第一个大写字母:”);
char ch = tw.getChar();
switch(ch) {
case ‘M’:
System.out.println(“Monday”);
break;
case ‘W’:
System.out.println(“Wednesday”);
break;
case ‘F’:
System.out.println(“Friday”);
break;
case ‘T’: {
System.out.println(“请输入星期的第二个字母:”);
char ch2 = tw.getChar();
if(ch2 == ‘U’) {System.out.println(“Tuesday”); }
else if(ch2 == ‘H’) {System.out.println(“Thursday”); }
else {System.out.println(“无此写法!”);
}
};
break;
case ‘S’: {
System.out.println(“请输入星期的第二个字母:”);
char ch2 = tw.getChar();
if(ch2 == ‘U’) {System.out.println(“Sunday”); }
else if(ch2 == ‘A’) {System.out.println(“Saturday”); }
else {System.out.println(“无此写法!”);
}
};
break;
default:System.out.println(“无此写法!”);
}
}
}
class getChar{
public char getChar() {
Scanner s = new Scanner(System.in);
String str = s.nextLine();
char ch = str.charAt(0);
if(ch<’A’ || ch>’Z’) {
System.out.println(“输入错误,请重新输入”);
ch=getChar();
}
return ch;
}
}
87. 简述求100之内的素数 ?
//使用除sqrt(n)的方法求出的素数不包括2和3
public class lianxi27 {
public static void main(String[] args) {
boolean b =false;
System.out.print(2 + ” “);
System.out.print(3 + ” “);
for(int i=3; i<100; i+=2) {
for(int j=2; j<=Math.sqrt(i); j++) {
if(i % j == 0) {b = false;
break;
} else{b = true;}
}
if(b == true) {System.out.print(i + ” “);}
}
}
}
//该程序使用除1位素数得2位方法,运行效率高通用性差。
public class lianxi27a {
public static void main(String[] args) {
int[] a = new int[]{2, 3, 5, 7};
for(int j=0; j<4; j++)System.out.print(a[j] + ” “);
boolean b =false;
for(int i=11; i<100; i+=2) {
for(int j=0; j<4; j++) {
if(i % a[j] == 0) {b = false;
break;
} else{b = true;}
}
if(b == true) {System.out.print(i + ” “);}
}
}
}
88. 简述对10个数进行排序 ?
import java.util.*;
public class lianxi28 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int[] a = new int[10];
System.out.println(“请输入10个整数:”);
for(int i=0; i<10; i++) {
a[i] = s.nextInt();
}
for(int i=0; i<10; i++) {
for(int j=i+1; j<10; j++) {
if(a[i] > a[j]) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
}
for(int i=0; i<10; i++) {
System.out.print(a[i] + ” “);
}
}
}
89. 求一个3*3矩阵对角线元素之和 ?
import java.util.*;
public class lianxi29 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int[][] a = new int[3][3];
System.out.println(“请输入9个整数:”);
for(int i=0; i<3; i++) {
for(int j=0; j<3; j++) {
a[i][j] = s.nextInt();
}
}
System.out.println(“输入的3 * 3 矩阵是:”);
for(int i=0; i<3; i++) {
for(int j=0; j<3; j++) {
System.out.print(a[i][j] + ” “);
}
System.out.println();
}
int sum = 0;
for(int i=0; i<3; i++) {
for(int j=0; j<3; j++) {
if(i == j) {
sum += a[i][j];
}
}
}
System.out.println(“对角线之和是:” + sum);
}
90. 简述有一个已经排好序的数组。现输入一个数,要求按原来的规律将它插入数组中。 ?
//此程序不好,没有使用折半查找插入
import java.util.*;
public class lianxi30 {
public static void main(String[] args) {
int[] a = new int[]{1, 2, 6, 14, 25, 36, 37,55};
int[] b = new int[a.length+1];
int t1 =0, t2 = 0;
int i =0;
Scanner s= new Scanner(System.in);
System.out.print(“请输入一个整数:”);
int num = s.nextInt();
if(num >= a[a.length-1]) {
b[b.length-1] = num;
for(i=0; i b[i] = a[i];
}
} else {
for(i=0; i if(num >= a[i]) {
b[i] = a[i];
} else {
b[i] = num;
break;
}
}
for(int j=i+1; j b[j] = a[j-1];
}
}
for (i = 0; i < b.length; i++) {
System.out.print(b[i] + ” “);
}
}
}
91. 简述将一个数组逆序输出 ?
import java.util.*;
public class lianxi31 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int a[] = new int[20];
System.out.println(“请输入多个正整数(输入-1表示结束):”);
int i=0,j;
do{
a[i]=s.nextInt();
i++;
}while (a[i-1]!=-1);
System.out.println(“你输入的数组为:”);
for( j=0; j System.out.print(a[j]+” “);
}
System.out.println(“\n数组逆序输出为:”);
for( j=i-2; j>=0; j=j-1) {
System.out.print(a[j]+” “);
}
}
}
92. 简述取一个整数a从右端开始的4~7位 ?
import java.util.*;
public class lianxi32 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.print(“请输入一个7位以上的正整数:”);
long a = s.nextLong();
String ss = Long.toString(a);
char[] ch = ss.toCharArray();
int j=ch.length;
if (j<7){System.out.println(“输入错误!”);}
else {
System.out.println(“截取从右端开始的4~7位是:”+ch[j-7]+ch[j-6]+ch[j-5]+ch[j-4]);
}
}
}
93. 简述打印出杨辉三角形(要求打印出10行如下图) ?
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
public class lianxi33 {
public static void main(String[] args) {
int[][] a = new int[10][10];
for(int i=0; i<10; i++) {
a[i][i] = 1;
a[i][0] = 1;
}
for(int i=2; i<10; i++) {
for(int j=1; j a[i][j] = a[i-1][j-1] + a[i-1][j];
}
}
for(int i=0; i<10; i++) {
for(int k=0; k<2*(10-i)-1; k++) {
System.out.print(” “);
}
for(int j=0; j<=i; j++) {
System.out.print(a[i][j] + “ “);
}
System.out.println();
}
}
}
94. 简述输入3个数a,b,c,按大小顺序输出 ?
import java.util.Scanner;
public class lianxi34 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.println(“请输入3个整数:”);
int a = s.nextInt();
int b = s.nextInt();
int c = s.nextInt();
if(a < b) {
int t = a;
a = b;
b = t;
}
if(a < c) {
int t = a;
a = c;
c = t;
}
if(b < c) {
int t = b;
b = c;
c = t;
}
System.out.println(“从大到小的顺序输出:”);
System.out.println(a + ” ” + b + ” ” + c);
}
}
95. 简述输入数组,最大的与第一个元素交换,最小的与最后一个元素交换,输出数组。 ?
import java.util.*;
public class lianxi35 {
public static void main(String[] args) {
int N = 8;
int[] a = new int [N];
Scanner s = new Scanner(System.in);
int idx1 = 0, idx2 = 0;
System.out.println(“请输入8个整数:”);
for(int i=0; i a[i] = s.nextInt();
}
System.out.println(“你输入的数组为:”);
for(int i=0; i System.out.print(a[i] + ” “);
}
int max =a[0], min = a[0];
for(int i=0; i if(a[i] > max) {
max = a[i];
idx1 = i;
}
if(a[i] < min) {
min = a[i];
idx2 = i;
}
}
if(idx1 != 0) {
int temp = a[0];
a[0] = a[idx1];
a[idx1] = temp;
}
if(idx2 != N-1) {
int temp = a[N-1];
a[N-1] = a[idx2];
a[idx2] = temp;
}
System.out.println(“\n交换后的数组为:”);
for(int i=0; i System.out.print(a[i] + ” “);
}
}
}
96. 简述有n个整数,使其前面各数顺序向后移m个位置,最后m个数变成最前面的m个数 ?
import java.util.Scanner;
public class lianxi36 {
public static void main(String[] args) {
int N =10;
int[] a = new int[N];
Scanner s = new Scanner(System.in);
System.out.println(“请输入10个整数:”);
for(int i=0; i a[i] = s.nextInt();
}
System.out.print(“你输入的数组为:”);
for(int i=0; i System.out.print(a[i] + ” “);
}
System.out.print(“\n请输入向后移动的位数:”);
int m = s.nextInt();
int[] b = new int[m];
for(int i=0; i b[i] = a[N-m+i];
}
for(int i=N-1; i>=m; i–) {
a[i] = a[i-m];
}
for(int i=0; i a[i] = b[i];
}
System.out.print(“位移后的数组是:”);
for(int i=0; i System.out.print(a[i] + ” “);
}
}
}
97. 有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位 ?
import java.util.Scanner;
public class lianxi37 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.print(“请输入排成一圈的人数:”);
int n = s.nextInt();
boolean[] arr = new boolean[n];
for(int i=0; i arr[i] = true;
}
int leftCount = n;
int countNum = 0;
int index = 0;
while(leftCount > 1) {
if(arr[index] == true) {
countNum ++;
if(countNum == 3) {
countNum =0;
arr[index] = false;
leftCount –;
}
}
index ++;
if(index == n) {
index = 0;
}
}
for(int i=0; i if(arr[i] == true) {
System.out.println(“原排在第”+(i+1)+”位的人留下了。”);
}
}
}
}
98. 简述写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度 ?
/*………………
*……题目意思似乎不能用length()函数 /
import java.util.;
public class lianxi38 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.println(“请输入一个字符串:”);
String str = s.nextLine();
System.out.println(“字符串的长度是:”+str.length());
}
}
99. 编写一个函数,输入n为偶数时,调用函数求1/2+1/4+…+1/n,当输入n为奇数时,调用函数1/1+1/3+…+1/n(利用指针函数) ?
//没有利用指针函数
import java.util.*;
public class lianxi39 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.print(“请输入一个正整数 n= “);
int n = s.nextInt();
System.out.println(“相应数列的和为:” + sum(n));
}
public static double sum(int n) {
double res = 0;
if(n % 2 == 0) {
for(int i=2; i<=n; i+=2) {
res += (double)1 / i;
}
} else {
for(int i=1; i<=n; i+=2) {
res += (double)1 / i ;
}
}
return res;
}
}
100. 简述字符串排序 ?
public class lianxi40 {
public static void main(String[] args) {
int N=5;
String temp = null;
String[] s = new String[N];
s[0] = “matter”;
s[1] = “state”;
s[2] = “solid”;
s[3] = “liquid”;
s[4] = “gas”;
for(int i=0; i for(int j=i+1; j if(compare(s[i], s[j]) == false) {
temp = s[i];
s[i] = s[j];
s[j] = temp;
}
}
}
for(int i=0; i System.out.println(s[i]);
}
}
static boolean compare(String s1, String s2) {
boolean result = true;
for(int i=0; i if(s1.charAt(i) > s2.charAt(i)) {
result = false;
break;
} else if(s1.charAt(i) result = true;
break;
} else {
if(s1.length() < s2.length()) {
result = true;
} else {
result = false;
}
}
}
return result;
}
}
101. 简述海滩上有一堆桃子,五只猴子来分 ?
海滩上有一堆桃子,五只猴子来分。第一只猴子把这堆桃子凭据分为五份,多了一个,这只猴子把多的一个扔入海中,拿走了一份。第二只猴子把剩下的桃子又平均分成五份,又多了一个,它同样把多的一个扔入海中,拿走了一份,第三、第四、第五只猴子都是这样做的,问海滩上原来最少有多少个桃子?
public class lianxi41 {
public static void main (String[] args) {
int i,m,j=0,k,count;
for(i=4;i<10000;i+=4)
{ count=0;
m=i;
for(k=0;k<5;k++)
{
j=i/4*5+1;
i=j;
if(j%40)
count++;
else break;
}
i=m;
if(count4)
{System.out.println(“原有桃子 “+j+” 个”);
break;}
}
}
}
102. 简述809*??=800*??+9*??+1 ?
809*??=800*??+9*??+1 其中??代表的两位数,8*??的结果为两位数,9*??的结果为3位数。求??代表的两位数,及809*??后的结果。
//题目错了!809x=800x+9x+1 这样的方程无解。去掉那个1就有解了。
public class lianxi42 {
public static void main (String[] args) {
int a=809,b,i;
for(i=10;i<13;i++)
{b=ia ;
if(8i<100&&9i>=100)
System.out.println (“809”+i+”=”+”800*”+i+”+”+”9*”+i+”=”+b);}
}
}
103. 简述求0—7所能组成的奇数个数 ?
//组成1位数是4个。
//组成2位数是74个。
//组成3位数是784个。
//组成4位数是7884个。
//……
public class lianxi43 {
public static void main (String[] args) {
int sum=4;
int j;
System.out.println(“组成1位数是 “+sum+” 个”);
sum=sum7;
System.out.println(“组成2位数是 “+sum+” 个”);
for(j=3;j<=9;j++){
sum=sum8;
System.out.println(“组成”+j+”位数是 “+sum+” 个”);
}
}
}
104. 简述一个偶数总能表示为两个素数之和 ?
//由于用除sqrt(n)的方法求出的素数不包括2和3,
//因此在判断是否是素数程序中人为添加了一个3。
import java.util.;
public class lianxi44 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int n,i;
do{
System.out.print(“请输入一个大于等于6的偶数:”);
n = s.nextInt();
} while(n<6||n%2!=0); //判断输入是否是>=6偶数,不是,重新输入
fun fc = new fun();
for(i=2;i<=n/2;i++){
if((fc.fun(i))1&&(fc.fun(n-i)1))
{int j=n-i;
System.out.println(n+” = “+i+” + “+j);
} //输出所有可能的素数对
}
}
}
class fun{
public int fun (int a) //判断是否是素数的函数
{
int i,flag=0;
if(a3){flag=1;return(flag);}
for(i=2;i<=Math.sqrt(a);i++){
if(a%i0) {flag=0;break;}
else flag=1;}
return (flag) ;//不是素数,返回0,是素数,返回1
}
}
//解法二
import java.util.;
public class lianxi44 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int n;
do{
System.out.print(“请输入一个大于等于6的偶数:”);
n = s.nextInt();
} while(n<6||n%2!=0); //判断输入是否是>=6偶数,不是,重新输入
for(int i=3;i<=n/2;i+=2){
if(fun(i)&&fun(n-i)) {
System.out.println(n+” = “+i+” + “+(n-i));
} //输出所有可能的素数对
}
}
static boolean fun (int a){ //判断是否是素数的函数
boolean flag=false;
if(a3){flag=true;return(flag);}
for(int i=2;i<=Math.sqrt(a);i++){
if(a%i0) {flag=false;break;}
else flag=true;}
return (flag) ;
}
}
105. 简述两个字符串连接程序 ?
import java.util.*;
public class lianxi46 {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.print(“请输入一个字符串:”);
String str1 = s.nextLine();
System.out.print(“请再输入一个字符串:”);
String str2 = s.nextLine();
String str = str1+str2;
System.out.println(“连接后的字符串是:”+str);
}
}
106. 简述某个公司采用公用电话传递数据,数据是四位的整数 ?
某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的,加密规则如下:每位数字都加上5,然后用和除以10的余数代替该数字,再将第一位和第四位交换,第二位和第三位交换。
import java.util.*;
public class lianxi48 {
public static void main(String args[]) {
Scanner s = new Scanner(System.in);
int num=0,temp;
do{
System.out.print(“请输入一个4位正整数:”);
num = s.nextInt();
}while (num<1000||num>9999);
int a[]=new int[4];
a[0] = num/1000; //取千位的数字
a[1] = (num/100)%10; //取百位的数字
a[2] = (num/10)%10; //取十位的数字
a[3] = num%10; //取个位的数字
for(int j=0;j<4;j++)
{
a[j]+=5;
a[j]%=10;
}
for(int j=0;j<=1;j++)
{
temp = a[j];
a[j] = a[3-j];
a[3-j] =temp;
}
System.out.print(“加密后的数字为:”);
for(int j=0;j<4;j++)
System.out.print(a[j]);
}
}
107. 简述计算字符串中子串出现的次数 ?
import java.util.*;
public class lianxi49 {
public static void main(String args[]){
Scanner s = new Scanner(System.in);
System.out.print(“请输入字符串:”);
String str1 = s.nextLine();
System.out.print(“请输入子串:”);
String str2 = s.nextLine();
int count=0;
if(str1.equals(“”)||str2.equals(“”))
{
System.out.println(“你没有输入字符串或子串,无法比较!”);
System.exit(0);
}
else
{
for(int i=0;i<=str1.length()-str2.length();i++)
{
if(str2.equals(str1.substring(i, str2.length()+i)))
//这种比法有问题,会把”aaa”看成有2个”aa”子串。
count++;
}
System.out.println(“子串在字符串中出现: “+count+” 次”);
}
}
}
108. 有五个学生,每个学生有3门课的成绩,从键盘输入以上数据(包括学生号,姓名,三门课成绩) ?
有五个学生,每个学生有3门课的成绩,从键盘输入以上数据(包括学生号,姓名,三门课成绩),计算出平均成绩,把原有的数据和计算出的平均分数存放在磁盘文件 “stud “中。
import java.io.;
import java.util.;
public class lianxi50 {
public static void main(String[] args){
Scanner ss = new Scanner(System.in);
String [][] a = new String[5][6];
for(int i=1; i<6; i++) {
System.out.print(“请输入第”+i+”个学生的学号:”);
a[i-1][0] = ss.nextLine();
System.out.print(“请输入第”+i+”个学生的姓名:”);
a[i-1][1] = ss.nextLine();
for(int j=1; j<4; j++) {
System.out.print(“请输入该学生的第”+j+”个成绩:”);
a[i-1][j+1] = ss.nextLine();
}
System.out.println(“\n”);
}
//以下计算平均分
float avg;
int sum;
for(int i=0; i<5; i++) {
sum=0;
for(int j=2; j<5; j++) {
sum=sum+ Integer.parseInt(a[i][j]);
}
avg= (float)sum/3;
a[i][5]=String.valueOf(avg);
}
//以下写磁盘文件
String s1;
try {
File f = new File(“C:\stud”);
if(f.exists()){
System.out.println(“文件存在”);
}else{
System.out.println(“文件不存在,正在创建文件”);
f.createNewFile();//不存在则创建
}
BufferedWriter output = new BufferedWriter(new FileWriter(f));
for(int i=0; i<5; i++) {
for(int j=0; j<6; j++) {
s1=a[i][j]+”\r\n”;
output.write(s1);
}
}
output.close();
System.out.println(“数据已写入c盘文件stud中!”);
} catch (Exception e) {
e.printStackTrace();
}
}
}
109. 判断101-200之间有多少个素数,并输出所有素数 ?
程序分析:判断素数的方法:用一个数分别去除2到sqrt(这个数),如果能被整除,
则表明此数不是素数,反之是素数。
import java.util.ArrayList;
public class Sushu {
public static void main(String[] args) {
ArrayList list = new ArrayList();
for(int i =101;i<=200;i++){
if(isPrime(i))
list.add(i);
}
System.out.println(list+“\n共有”+list.size()+“个素数”);
}
public static boolean isPrime(int i){
boolean flag = true;
for(int j =2;j<=Math.sqrt(i);j++){
if(i%j==0){
flag = false;
}
}
return flag;
110. 简述括号匹配 ?
字符串中只有左右小括号,判断是否匹配。
可以用栈,也可以不用。
设置一个变量 num:、
遍历字符串
1)遇到左括号,num++
2)遇到右括号,num–,如果 num<0,返回 false
3)遍历完后,num 为 0,返回 true,否则返回 false
时间复杂度为 O(n)
ublic boolean isBracketMatch() {
int num = 0;
for (char c : value) {
if (c == ‘(’) {
num++;
} else if (c == ‘)’) {
num–;
if (num < 0) {
return false;
}
}
}
return num == 0;
}
111. 简述如何实现最长无重复子串长度 ?
比如”abcb”,其最长无重复子串为”abc”,长度为 3
比如”abcd”,长度为 4
时间复杂度为 O(n),空间复杂度为 O(n)
求出以每个字符结尾的子串中,每个子串的最长无重复子串,取其 max。
求 i 位置的最长无重复子串长度:
使用一个哈希表 Map,键是字符,值是该字符上次出现位置
使用一个变量 preStart,记录了以 i-1 结尾的最长无重复子串的开始位置,本次遍历时更新
为以 i 结尾的最长无重复子串的开始位置
使用一个变量 currentLen,记录了以 i 结尾的无重复子串的长度
使用一个变量 maxLen,记录了历史最长无重复子串的长度,取 MAX(maxLen,currentLen)
步骤:
1)求 map.get(str[i])的位置 A,如果没有,则 A 为 0
2)求 preStart 的位置 B
3)取 max(A+1,B),将 preStart 与 max(A+1,B)到 i 的长度进行比较,取较大值更新 preStart
4)计算 currentLen,更新 maxLen 为 maxLen 与 currentLen 的较大值
5)更新 map,map.put(str[i].i)
**
- 最长无重复子串长度
- 比如 ”abcb” ,其最长无重复子串为 ”abc” ,长度为 3
- 比如 ”abcd” ,长度为 4
- 时间复杂度为 O(n) ,空间复杂度为 O(n)
- @return
*/
public int longestLengthOfUniqueSubstring() {
// 记录了 i-1 位置上的最长无重复子串的开始下标
int preStart = 0;
int currentLen = 0;
int maxLen = 0;
Map lastIndex = new HashMap<>();
for (int i = 0; i < value.length; i++) {
if (lastIndex.get(value[i]) != null) {
preStart = Math.max(lastIndex.get(value[i]) + 1, preStart);
}
// 此时 currentStart 指向了如果以 i 位置为结尾,最长的子串的开始位置
// currentLen 是当前最长子串长度
currentLen = i - preStart + 1;
// 取较长字符长度
maxLen = Math.max(maxLen, currentLen);
// 一定要更新当前字符,可以舍弃前面的重复字符,但绝不能舍弃当前的重复字符
// 比如 rfrabc,遇到第二个 r 时一定要舍弃前一个 r(pre 前进),而不能舍弃第二
个 r
lastIndex.put(value[i], i);
}
return maxLen;
}
112. 简述如何实现替换空格 ?
**
- 空格替换,将空格替换为 %20 ,其他的不变
微信公众号:程序员乔戈里 - 双指针,都是从后向前移动,直至 old 指针指向头或者双指针相交
- @param sb
- @return
*/
public static String replaceSpace(StringBuilder sb) {
int spaceCount = 0;
for (int i = 0; i < sb.length(); i++) {
if (sb.charAt(i) == ’ ') {
spaceCount++;
}
}
int oldIndex = sb.length() - 1;
sb.setLength(sb.length() + spaceCount * 2);
for (int i = oldIndex + spaceCount * 2; i >= oldIndex && oldIndex >= 0;
oldIndex–) {
if (sb.charAt(oldIndex) == ’ ') {
sb.setCharAt(i–, ‘0’);
sb.setCharAt(i–, ‘2’);
sb.setCharAt(i–, ‘%’);
} else {
sb.setCharAt(i–, sb.charAt(oldIndex));
}
}
return sb.toString();
}
113. 简述如何计算第一个只出现一次的字符 ?
/**
- 哈希表
- 因为哈希表大小与 str 的长度无关
- 所以空间复杂度为 O(1)
- 时间复杂度为 O(n)
- @param str
- @return
*/
public static int appearOnceIndex(String str) {
int[] map = new int[256];
for (int i = 0; i < str.length(); i++) {
map[str.charAt(i)]++;
}
System.out.println(Arrays.toString(map));
for (int i = 0; i < str.length(); i++) {
if(map[str.charAt(i)] == 1) {
return i;
}
}
return -1;
}
114. 简述Java实现快速排序非递归实现 ?
/**
- 栈中存放着应该调用 partition 的 low 和 high 指针
- @param arr
- @param low
- @param high
*/
public static void quickSortNoRec(int[] arr, int left, int right) {
Stack stack = new Stack<>();
if (left < right) {
stack.push(left);
stack.push(right);
while (!stack.isEmpty()) {
int high = stack.pop();
int low = stack.pop();
int pivotIndex = partition(arr, low, high);
if (low < pivotIndex - 1) {
stack.push(low);
stack.push(pivotIndex - 1);
}
if (pivotIndex + 1 < high) {
stack.push(pivotIndex + 1);
stack.push(high);
}
}
}
}
115. 简述Java实现数组中出现次数超过一半的数字/ / 中位数(类似于快速排序 ) ?
/**
- 返回数组中出现次数超过一半的数字
- 使用类似于快速排序的思想
- @param arr
- @return
/
public static int moreThanHalf(int[] arr) {
if (arr == null || arr.length == 0) {
return 0;
}
int low = 0;
int high = arr.length - 1;
int index = QuickSort.partition(arr, low, high);
int mid = (low + high) / 2;
while (index != mid) {
if (index > mid) {
index = QuickSort.partition(arr, low, index - 1);
} else {
index = QuickSort.partition(arr, index + 1, high);
}
}
if(!checkMoreThanHalf(arr,arr[index])) {
return 0;
}
return arr[index];
}
/* - 检查 number 是否真的超过了一般
- @param arr
- @param number
- @return
*/
private static boolean checkMoreThanHalf(int[] arr, int number) {
int times = 0;
for (int i = 0; i < arr.length; i++) {
if(arr[i] == number) {
times++;
}
}
return times * 2 > arr.length;
}
116. 简述计算无序数组中的第 k k 大元素(基于 partition ) ?
第一次交换,算法复杂度为 O(N),接下来的过程和快速排序不同,快速排序是要继续处理
两边的数据,再合并,合并操作的算法复杂度是 O(1),于是总的算法复杂度是 O(N*logN)
(可以这么理解,每次交换用了 N,一共 logN 次)。但是这里在确定枢纽元的相对位置(在
K 的左边或者右边)之后不用再对剩下的一半进行处理。也就是说第二次插入的算法复杂度
不再是 O(N)而是 O(N/2),这不还是一样吗?其实不一样,因为接下来的过程是
1+1/2+1/4+… < 2,换句话说就是一共是 O(2N)的算法复杂度也就是 O(N)的算法复杂度
凡是每次取一半进行 partation 的时间复杂度都为 2N
/**
- 无序数组中找到第 k 大元素
- @param arr
- @return
*/
public static int findKth(int[] arr, int k) {
if(arr == null || arr.length == 0 || k < 0) {
throw new IllegalArgumentException();
}
int low = 0;
int high = arr.length - 1;
int index = QuickSort.partition(arr, low, high);
while (index != k) {
if (index < k) {
index = QuickSort.partition(arr, index + 1, high);
} else {
index = QuickSort.partition(arr, low, index - 1);
}
}
return arr[index];
}
117. 简述Java如何找出数据流中的中位数 ?
private int count = 0;
private PriorityQueue minHeap = new PriorityQueue<>();
private PriorityQueue maxHeap = new PriorityQueue<>(new
Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
/**
- 把所有的数字分为两部分,数据总数为偶数时,新加入的元素与大根堆中所有元素比较,最
大值进入小根堆 - 数据总数为奇数时,新加入的元素与小根堆中所有元素比较,最小值进入大根堆
- 结果就是:大根堆存放较小的一部分数字,小根堆存放较大的一部分数字
- 当数据总数为偶数时,中位数为 ( 大根堆顶 + 小根堆顶 )/2
- 当数据总数为奇数时,小根堆总数比大根堆多一个,中位数即为小根堆顶
- @param num
*/
public void insert(int num) {
if ((count & 1) == 0) {
maxHeap.add(num);
minHeap.add(maxHeap.poll());
}else{
minHeap.add(num);
maxHeap.add(minHeap.poll());
}
count++;
}
public double getMedian() {
if((count & 1) == 0){
return 1.0 * (minHeap.peek() + maxHeap.peek()) / 2;
}else{
return 1.0 * minHeap.peek();
}
}
118. 简述Java实现有序数组合并 ?
/**
- 将 a 和 b 两个有序数组合并至 a 中
- a 的长度是 a 的有效元素长度 +b 的长度
- @param a
- @param b
- @return
*/
public static void merge(int[] a, int[] b) {
int i = a.length - b.length - 1;
int j = b.length - 1;
int merge = a.length - 1;
while (i >= 0 && j >= 0) {
if (a[i] <= b[j]) {
a[merge] = b[j];
merge–;
j–;
} else {
a[merge] = a[i];
merge–;
i–;
}
}
// 因为是从后向前遍历,这样不需要把 a 的重新拷贝回 a
while(j >= 0) {
a[merge] = b[j];
merge–;
j–;
}
}
119. 简述Java实现有序矩阵搜索 ?
/**
- 矩阵行列有序,查找指定元素是否存在
- 从矩阵右上角开始找, i 是行指针, j 是列指针
- 如果大于 target ,那么 j–
- 如果小于 target ,那么 i++ ,直至找到或者越界
- @param matrix
- @param target
- @return
*/
public static boolean search(int[][] matrix, int target) {
int i = 0;
int j = matrix[0].length - 1;
while (i >= 0 && j >= 0 && i < matrix.length && j < matrix[0].length) {
if (matrix[i][j] > target) {
j–;
} else if (matrix[i][j] < target) {
i++;
} else {
return true;
}
}
return false;
}
120. 简述需要排序的最短子数组长度 ?
public static int lenOfShortestSubArray(int[] arr) {
int min = Integer.MAX_VALUE;
int max = 0;
int minIndex = 0;
int maxIndex = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
} else if (arr[i] < max) {
maxIndex = i;
}
}
for (int i = arr.length - 1; i >= 0; i–) {
if (arr[i] < min) {
min = arr[i];
} else if (arr[i] > min) {
minIndex = i;
}
}
// 如果 minIndex 和 maxIndex 相同,那么返回 0
if (minIndex == maxIndex) {
return 0;
} else {
return maxIndex - minIndex + 1;
}
}
121. 简述Java实现三色排序(类似快排) ?
/**
- 三色排序问题
- 1 )若遍历到的位置为 0 ,则说明它一定属于前部,于是就和 begin 位置进行交换,然后 current
向前进, begin 也向前进(表示前边的已经都排好了)。 - 2 )若遍历到的位置为 1 ,则说明它一定属于中部,根据总思路,中部的我们都不动,然后
current 向前进。 - 3 )若遍历到的位置为 2 ,则说明它一定属于后部,于是就和 end 位置进行交换,由于交换
完毕后 current 指向的可能是属于前部的,若此时 current 前进则会导致该位置不能被交换到
前部,所以此时 current 不前进。而同 1 ), end 向后退 1 。 - @param arr
*/
public static void sort(int[] arr) {
int after0 = 0;
int before2 = arr.length - 1;
int current = 0;
while (current <= before2) {
if (arr[current] == 0) {
swap(arr, after0, current);
current++;
after0++;
} else if (arr[current] == 2) {
swap(arr, before2, current);
before2–;
} else {
current++;
}
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
122. 简述Java实现数组中所有数对的最大差值 ?
/**
- 数组中数对的最大差值,要求较大的数字位置在较后面
- 最简单的算是二层循环,时间复杂度为 O(n^2)
- min 始终保存着最小值
- currentDiff(i) = 较大的数字位置为 i 时的差值 = arr[i] - min
- 时间复杂度为 O(n)
- @param arr
- @return
*/
public static int maXDiff(int[] arr) {
if (arr == null || arr.length < 2) {
return 0;
}
int min = arr[0];
int maxDiff = Integer.MIN_VALUE;
int currentDiff;
for (int i = 1; i < arr.length; i++) {
currentDiff = arr[i] - min;
if (arr[i] < min) {
min = arr[i];
}
if (currentDiff > maxDiff) {
maxDiff = currentDiff;
}
}
return maxDiff;
}
123. 简述如何实现数组中邻近数对的最大差值 ?
public static int maxGap(int[] arr) {
int min = Integer.MAX_VALUE;
int max = 0;
for (int i = 0; i < arr.length; i++) {
min = Math.min(min, arr[i]);
max = Math.max(max, arr[i]);
}
int n = arr.length;
// bucket 中只存储最小值和最大值
int[] minBucket = new int[n + 1];
int[] maxBucket = new int[n + 1];
boolean[] isEmptyBucket = new boolean[arr.length + 1];
Arrays.fill(minBucket,Integer.MAX_VALUE);
Arrays.fill(isEmptyBucket,true);
int bucketNumber;
for (int i = 0; i < n; i++) {
bucketNumber = bucketNumber(arr[i], n, min, max);
System.out.println(“data:”+arr[i]+“,bucketNumber:”+bucketNumber);
minBucket[bucketNumber] = isEmptyBucket[bucketNumber] ? arr[i] :
Math.min(minBucket[bucketNumber], arr[i]);
maxBucket[bucketNumber] = isEmptyBucket[bucketNumber] ? arr[i] :
Math.max(maxBucket[bucketNumber], arr[i]);
isEmptyBucket[bucketNumber] = false;
}
// 桶填充完毕
int maxGap = 0;
int i = 0;
int priorMax = 0;
while (i < n + 1) {
// 寻找第一个空桶,取其前一个桶的最大值
while (i < n + 1 && !isEmptyBucket[i]) {
i++;
}
if (i == n + 1) {
return maxGap;
}
// 前一个桶的最大值
priorMax = maxBucket[i - 1];
// 寻找之后的第一个非空桶,取其最小值,相减即为 gap
// 遍历一遍,得到 maxGap
while (i < n + 1 && isEmptyBucket[i]) {
i++;
}
if (i == n + 1) {
return maxGap;
}
maxGap = Math.max(maxGap,minBucket[i] - priorMax);
}
return maxGap;
}
private static int bucketNumber(int value, int n, int min, int max) {
return (int) (1.0 * (value - min) * n / (max - min));
}
124. 简述简单实现简单二分搜索 ?
时间复杂度为 O(log n),必须使用在有序序列中。但二分搜索未必仅适用于有序序列。
public static int binarySearch(int[] arr, int key) {
int low = 0;
int high = arr.length - 1;
int mid = 0;
while (low <= high) {
mid = (low + high) / 2;
if (key > arr[mid]) {
low = mid + 1;
}else if(key < arr[mid]) {
high = mid - 1;
}else {
return mid;
}
}
// 当 low>high 且 该索引处的值不为 key,则表示没有找到
return -1;
}
125. 简述二分搜索最小位置(Java实现) ?
public static int binarySearchMinPosition(int[] arr, int key) {
int low = 0;
int high = arr.length - 1;
int mid = 0;
int result = -1;
while (low <= high) {
mid = (low + high) / 2;
if (key <= arr[mid]) {
high = mid - 1;
if (key == arr[mid]) {
result = mid;
}
} else {
low = mid + 1;
}
}
126. 简述二分搜索最大位置(Java实现) ?
public static int binarySearchMaxPosition(int[] arr, int key) {
int low = 0;
int high = arr.length - 1;
int mid = 0;
int result = -1;
while (low <= high) {
mid = (low + high) / 2;
if (key >= arr[mid]) {
low = mid + 1;
if (key == arr[mid]) {
result = mid;
}
} else {
high = mid - 1;
}
}
return result;
}
127. 简述Java有序数组中某个数字的出现次数 ?
/**
- 有序数组中某个数字的出现次数
- 时间复杂度为 O(log n)
- @param arr
- @param key
- @return
*/
public static int getAppearTimes(int[] arr, int key) {
int min = BinarySearch.binarySearchMaxPosition(arr, key);
int max = BinarySearch.binarySearchMinPosition(arr, key);
if (min != -1 && max != -1) {
if (min == max) {
return 1;
} else {
return max - min - 1;
}
} else {
return 0;
}
}
128. 简述Java实现搜索任意一个局部最小的位置 ?
给定一个无序数组 arr,已知任意相邻的两个元素值都不重复,返回任意一个局部最小的位
置。
局部最小是指:
1)arr[0] < arr[1] ,0 是局部最小的位置
2)arr[N-1] < arr[N-2],N-1 是局部最小的位置
3)arr[i] < arr[i-1] && arr[i] < arr[i+1],i 是局部最小的位置
要求时间复杂度为 O(logn)
未必一定要求数组有序,只要能在比较时淘汰一半,留下另一半,就可以实现 O(logn)
/**
- 给定无序数组 arr ,已知 arr 中任意两个相邻的数都不相等,写一个函数,只需返回 arr 中
任意一个局部最小出现的位置即可。 - 搜索任意一个局部最小的位置
- 局部最小是指:
- 1 ) arr[0] < arr[1] , 0 是局部最小的位置
- 2 ) arr[N-1] < arr[N-2] , N-1 是局部最小的位置
- 3 ) arr[i] < arr[i-1] && arr[i] < arr[i+1] , i 是局部最小的位置
- 时间复杂度为 O(log n)
- @param arr
- @return
*/
public static int search(int[] arr) {
if (arr.length == 0) {
return -1;
}
微信公众号:程序员乔戈里
if (arr.length == 1) {
return 0;
}
// 至少有两个元素
if (arr[0] < arr[1]) {
return 0;
}
if (arr[arr.length - 1] < arr[arr.length - 2]) {
return arr.length - 1;
}
int low = 1;
int high = arr.length - 2;
int mid = 0;
while (low <= high) {
mid = (low + high) / 2;
if (arr[mid] < arr[mid - 1] && arr[mid] < arr[mid + 1]) {
return mid;
}
if (arr[mid] > arr[mid - 1]) {
high = mid - 1;
} else if (arr[mid] > arr[mid + 1]) {
low = mid + 1;
}
}
return -1;
}
129. 简述Java循环有序数组的最小值的计算 ?
循环有序数组是指:有序数组左边任意长度的部分放到右边去,右边的部分拿到左边来、
比如数组【1,2,3,4,5】,是有序循环数组,【4,1,2,3,3】也是。
算法:
令 low 初值为 0,high 初值为 N-1.。
1)首先判断 arr[low] 序数组,没有循环部分,那么最小值即为 arr[0]
2)mid 为 low 和 high 的中间位置。
如果 arr[mid] < arr[low],那么说明最小值一定在 low 与 mid(包含 mid)之间,high = mid ,
因为 mid 一定处于循环部分。比如【7,8,9,1,2,3,4,5,6】。进入下次循环。
如果 arr[mid] > arr[high],那么说明最小值一定在 mid(不含 mid)与 high 之间,low = mid
+1,因为 mid 一定处于循环部分。比如【4,5,6,7,8,9,1,2,3】。进入下次循环。
3)如果都不满足,那么说明 arr[low]=arr[high]=arr[mid]。此时无法使用二分查找,只能遍
历数组去查找最小值,查找到后返回
/**
- 令 low 初值为 0 , high 初值为 N-1. 。
- 1 )首先判断 arr[low] 的有序数组,没有循环部分,那么最小值即为 arr[0] (唯一的返回位置)
- 2 ) mid 为 low 和 high 的中间位置。
- 如果 arr[mid] < arr[low] ,那么说明最小值一定在 low 与 mid 之间, high = mid ,因
为 mid 一定处于循环部分。比如【 7,8,9,1,2,3,4,5,6 】。进入下次循环。 - 如果 arr[mid] > arr[high] ,那么说明最小值一定在 mid 与 high 之间, low = mid + 1 ,
因为 mid 一定处于循环部分。比如【 4,5,6,7,8,9,1,2,3 】。进入下次循环。 - 3 )如果都不满足,那么说明 arr[low]=arr[high]=arr[mid] 。此时无法使用二分查找,
只能遍历数组去查找最小值。 - @param arr
- @return
*/
public static int findMin(int[] arr) {
int low = 0;
int high = arr.length - 1;
int mid = 0;
int min = Integer.MAX_VALUE;
while (true) {
mid = (low + high) / 2;
// case 1
if (arr[low] < arr[high]) {
return arr[low];
} else if (arr[mid] < arr[low]) {
// 最小值可能是 mid,也可能在 mid 左边
high = mid;
} else if (arr[mid] > arr[high]) {
// 最小值一定在 mid 右边
low = mid + 1;
} else {
// arr[low] == arr[mid] == arr[high]
// 无法进行二分搜索,转为顺序搜索
for (int i = low; i <= high; i++) {
min = Math.min(min, arr[i]);
}
return min;
}
}
}
130. 简述如何实现最左侧『数值和下标相等』的元素 ?
给定一个不含有重复元素的有序数组 arr,找出 arr[i]==i 的最左位置。如果不存在,返回-1。
算法:
low = 0,high = N-1
result = -1
1)如果 arr[0] > N -1 ,则一定不存在,返回-1
2)如果 arr[N-1] < 0,则一定不存在,返回-1
3)mid 为 low 和 high 的中间位置。如果 arr[mid] > mid,则说明 mid 右边一定不存在 arr[i]
==i(因为右边索引增量恒为 1,数值增量至少为 1,差距只会增加不会变小),此时另 high
= mid – 1。
4)如果 arr[mid] < mid,则说明左边一定不存在 arr[i] == i,原因同上,此时令 low = mid +
1。
5)如果 arr[mid] == mid,则记录 result 为 mid,因为要找最左位置,所以也令 high = mid – 1。
直至 low>high、
/**
- 给定一个不含有重复元素的有序数组 arr ,找出 arr[i]==i 的最左位置。如果不存在,返回
-1 。 - 算法:
- low = 0,high = N-1
- result = -1
- 1 )如果 arr[0] > N-1 ,则一定不存在,返回 -1
- 2 )如果 arr[N-1] < 0 ,则一定不存在,返回 -1
- 3 ) mid 为 low 和 high 的中间位置。如果 arr[mid] > mid ,则说明 mid 右边一定不存在
arr[i] ==i (因为右边索引增量恒为 1 ,数值增量至少为 1 ,差距只会增加不会变小),此时
另 high = mid – 1 。 - 4 )如果 arr[mid] < mid ,则说明左边一定不存在 arr[i] == i ,原因同上,此时令 low =
mid + 1 。 - 5 )如果 arr[mid] == mid, 则记录 result 为 mid ,因为要找最左位置,所以也令 high = mid
– 1 。 - 直至 low>high 、
- @param arr
- @return
*/
public static int minPosition(int[] arr) {
if (arr.length == 0) {
return -1;
}
if (arr[0] > arr.length - 1 || arr[arr.length - 1] < 0) {
return -1;
}
int low = 0;
int high = arr.length - 1;
int mid = 0;
int result = -1;
while (low <= high) {
mid = (low + high) / 2;
// 舍弃右边
if (arr[mid] >= mid) {
high = mid - 1;
if (arr[mid] == mid) {
result = mid;
}
} else {
// 舍弃左边
low = mid + 1;
}
}
return result;
}
131. 简述Java如何实现完全二叉树计数 ?
给定一颗完全二叉树的头节点 head,返回这棵树的节点个数。如果完全二叉树的节点数为
N,实现时间复杂度为 O(h2)/O(logn2)的解法。
完全二叉树要求插入和删除都必须在叶节点、插入时叶节点满则新增一层。
count(treenode)
1)找到二叉树左子树最左节点,同时统计二叉树高度 leftH
2)找到二叉树右子树最右节点,同时统计二叉树高度 rightH
3)如果两个高度相同,那么说明左子树是一棵满二叉树,已知高度,节点数为 2^h -1,再
加上头节点的 1,剩余的节点(右子树)可以采用递归的方法计算。求和即为总数。
4)如果两个高度不同,那么说明右子树也是一棵满二叉树,只是比左子树少一层。可以根
据公式求得右子树的个数,加上头节点的 1,剩余的节点(左子树)可以采用递归的方法计
算,求和即为总数。
为什么是 O(h^2) h = logN ?
每一层高度,都要去递归算一次高度(h-1)
/**
- 给定一颗完全二叉树的头节点 head ,返回这棵树的节点个数。如果完全二叉树的节点数为 N ,
实现时间复杂度为 O(h2)/O(logn2) 的解法。 - 完全二叉树要求插入和删除都必须在叶节点、插入时叶节点满则新增一层。
- count(treenode)
- 1 )找到二叉树左子树最左节点,同时统计二叉树高度 leftH
- 2 )找到二叉树右子树最右节点,同时统计二叉树高度 rightH
- 3 )如果两个高度相同,那么说明左子树是一棵满二叉树,已知高度,节点数为 2^h -1 ,再
加上头节点的 1 ,剩余的节点(右子树)可以采用递归的方法计算。求和即为总数。
微信公众号:程序员乔戈里 - 4 )如果两个高度不同,那么说明右子树也是一棵满二叉树,只是比左子树少一层。可以根
据公式求得右子树的个数,加上头节点的 1 ,剩余的节点(左子树)可以采用递归的方法计算,
求和即为总数。 - @param root
- @return
*/
private int countCompleteBinaryTree(TreeNode root) {
if (root == null) {
return 0;
}
TreeNode leftSubTree = root.left;
int leftHeight = 0;
while (leftSubTree != null) {
leftHeight++;
leftSubTree = leftSubTree.left;
}
TreeNode rightSubTree = root.right;
int rightHeight = 0;
while (rightSubTree != null) {
rightHeight++;
rightSubTree = rightSubTree.left;
}
if (leftHeight == rightHeight) {
return (int) Math.pow(2, leftHeight) +
countCompleteBinaryTree(root.right);
} else {
return (int) Math.pow(2, rightHeight) +
countCompleteBinaryTree(root.left);
}
}
132. 简述Java实现快速 N 次方 ?
求一个整数 k 的 N 次方,如果两个整数相乘的时间复杂度为 O(1),实现时间复杂度为 O(logn)
的解法。
设置当前算子(curr)初值为 k。
将 N 转为二进制形式,从最后一位开始从后向前遍历。
如果当前位为 1,那么 result * curr,否则 result 不变。
curr 乘其自身(指数翻倍),N 右移。
直至 N 为 0。
/**
- 求 k 的 n 次方,结果对 mod 取余(避免溢出)
- 设置当前算子( curr )初值为 k 。
- 将 N 转为二进制形式,从最后一位开始从后向前遍历。
- 如果当前位为 1 ,那么 result * curr ,否则 result 不变。
- curr 乘其自身(指数翻倍), N 右移。
- 直至 N 为 0 。
- 时间复杂度为 O(log n)
- @param base
- @param exp
- @return
*/
public static double power(double base, int exp) {
if (Double.compare(base, 0) == 0 && exp < 0) {
throw new IllegalArgumentException(“0 的负数次方不存在”);
}
if (exp == 0) {
// 这里假定 0 的 0 次方为 1
return 1;
}
if (exp == 1) {
return base;
}
double result = 1;
double curr = 0;
if (exp > 0) {
curr = base;
} else {
curr = 1 / base;
}
exp = exp > 0 ? exp : -exp;
while (exp != 0) {
// 如果 n 的最低位为 1
if ((exp & 1) == 1) {
result *= curr;
}
exp >>= 1;
curr *= curr;
}
return result;
}
133. 简述二进制中 1 的个数 ?
/**
- 计算 n 的二进制中 1 的个数
- 是将一个数字每次左移,与 n 取与判断每位是否是 1
- @param n
- @return
/
public static int countOne(int n) {
int count = 0;
int onePosition = 1;
while (onePosition != 0) {
if ((n & onePosition) != 0) {
count++;
}
onePosition <<= 1;
}
return count;
}
/* - 如果是 n 算术右移的话,如果是负数,那么左侧会不断补 1 ,这样计算结果就错了
- 这里 n 是逻辑右移,始终补 0 ,不会补符号位
- @param n
- @return
*/
public static int countOne2(int n) {
int count = 0;
while(n != 0) {
if((n & 1) == 1) {
count++;
}
n >>>= 1;
}
return count;
}
134. 简述Java判断是否是 2 ?
public static boolean is2Power(int n) {
return (n & n - 1) == 0;
}
如果 n 是 2 的幂次中,那么只有一个位是 1,n-1 再与 n 做与运算,此时所有位都是 0.
比如
16 = 0001 0000
16-1=15= 0000 1111
16 & 15 = 0000 0000
2 的幂次减一时,唯一的 1 前面的 0 还是 0,1 变为 0,后面的 0 都变为了 1,所以再与本身
做与运算时,全都是 0
135. 简述求一个数的临近的较大的 2 的幂次( HashMap ) ?
public static int nearestUpper2Power(int n) {
if ((n & (n - 1)) == 0) {
return n;
}
// 从最高 bit 位为 1 的位开始,从左边往右边复制 bit 位为 1 到相邻的 bit 位
// 报政府从最高 bit 位为 1 的位开始,之后全为 1,
// 这样加 1,结果就是 2 的幂次了
n = n - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return n + 1;
}
136. 简述Java数字序列中某一位的数字 ?
/**
- 数字序列 0123456789101112…
- 求第 k 位对应的数字
- 前 10 位是 0~9 的一位数
- 向后 180 位是 10~99 的两位数
- 向后 2700 位是 100~999 的三位数
- @param k
- @return
/
public static int findKthNumber(int k) {
if (k < 0) {
return -1;
}
// base=1 表示一位数,2 表示二位数
// baseNumberCount 表示 base 位数共有多少个数字(不包含 base 以下位数的数字)
// baseNumberCountbase 表示 base 位数 共有多少位
int base = 1;
while (true) {
int baseNumberCount = countBase(base);
if (k < baseNumberCount * base) {
return findKthNumber(k, base);
}
k -= baseNumberCount * base;
base++;
}
}
/** - base 位数共有多少个数字
- @param base
- @return
/
private static int countBase(int base) {
if (base == 1) {
return 10;
}
return 9 * (int) Math.pow(10, base - 1);
}
/* - 求在 base 位数中的第 k 位
- 比如三位数中的第 38 位: 100101102103104105106107108109110111112113114… -> 2
- @param k
- @param base
- @return
*/
private static int findKthNumber(int k, int base) {
int number = baseBeginNumber(base) + k / base;
int kFromRight = base - k % base;
for (int i = 1; i < kFromRight; i++) {
number /= 10;
}
return number % 10;
}
private static int baseBeginNumber(int base) {
if (base == 1) {
return 0;
}
return (int) Math.pow(10, base - 1);
}
137. 简述Java寻找重复数字(整数范围内) bitmap ?
bitmap
用 hash 方法,建一个 2 的 32 次方个 bit 的 hash 数组,每取一个 int 数,可 hash 下 2 的 32
次方找到它在 hash 数组中的位置,然后将 bit 置 1 表示已存在。
时间复杂度为 O(n),空间复杂度为 O(1),实际是占用了 232/8=229byte。
java.util.BitSet
public static Set findDuplicateIntegers(int[] arr) {
Set result = new HashSet<>();
BitSet bitmap = new BitSet(Integer.MAX_VALUE);
for (int i = 0; i < arr.length; i++) {
if(bitmap.get(arr[i])){
result.add(arr[i]);
}else{
bitmap.set(arr[i]);
}
}
return result;
}
138. 简述Java求一个字符集合的所有可能子集 t int s as bitmap ?
给定字母集合(a-z), 求出由集合中这些字母组成的所有非空子集
/**
- 列出一个集合中的所有非空子集
- 含 n 个元素的集合有 2^n - 1 个子集,因此算法的时间复杂度为 O(2^n)
- @param str
- @return
*/
public static List listAllSubSets(String str) {
List result = new ArrayList<>();
if (str.length() == 0) {
return result;
}
char[] chars = str.toCharArray();
int bitmap = 0;
// 原字符串“aefea” bitmap 二进制为 00…00110001(共 26 位)
for (int i = 0; i < chars.length; i++) {
// 如果 a 存在,那么 bitmap 倒数第一位置为 1
// 如果 z 存在,那么 bitmap 倒数第 26 位置为 1
bitmap |= 1 << (chars[i] - ‘a’);
}
System.out.println(Integer.toBinaryString(bitmap));
int key;
int charIndex;
// 每次打印一个子集
StringBuilder sb = new StringBuilder();
for (int i = 1; i < Math.pow(2, str.length()); i++) {
key = i & bitmap;
charIndex = 0;
while(key != 0) {
// key 就是要打印的字符串对应的 bit 们
// while 循环逐个找出要打印的字符
if((key & 1) == 1) {
sb.append((char)(‘a’ + charIndex));
}
key >>= 1;
charIndex++;
}
result.add(sb.toString());
sb.delete(0,sb.length());
}
return result;
}
public static void main(String[] args) {
System.out.println(listAllSubSets(“abc”));
}

被折叠的 条评论
为什么被折叠?



