交会修理你的朋友。这种朋友正是你人生的导师。
1.加一
/**
*给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
* 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。
* 你可以假设除了整数 0 之外,这个整数不会以零开头。
*
* 示例 1:
* 输入: [1,2,3]
* 输出: [1,2,4]
* 解释: 输入数组表示数字 123。
*
* 示例 2:
* 输入: [4,3,2,1]
* 输出: [4,3,2,2]
* 解释: 输入数组表示数字 4321。
*/
题目中说给你一个数组,该数组表示的是一个数字,现在要加一然后返回该数字对应的数组。很简单的一道题,需要注意的就是进位问题。最简单的思路就是先把数组从后往前相加并处理进位,将他们存入一个List,最后根据List长度来创建数组并返回。
public static int[] method1(int[] digits) {
ArrayList<Integer> integerList=new ArrayList<>();
int overflow=1;
for (int i=digits.length-1;i>=0;i--){
integerList.add((digits[i]+overflow)%10);
if (digits[i]+overflow>9){
overflow=1;
}else {
overflow=0;
}
}
if (overflow==1) integerList.add(1);
Collections.reverse(integerList);
int[] nums=new int[integerList.size()];
for (int i=0;i<nums.length;i++){
nums[i]=integerList.get(i);
}
return nums;
}
当然上面这种歌算法不是最快的方法,因为涉及到了List,Java中的List是基于数组实现的可变长数组,所以效率较低,想要高效率那就是全数组,分两种情况考虑,一种是第一位等于10,发生了进位,原数组装不下了,必须创建新的数组,另一种就是第一位小于10,原数组可以装下新的数值。
private static int[] method2(int[] digits){
if(digits==null||digits.length==0) {
return null;
}
int i;
int len=digits.length;
digits[len-1]+=1;
for(i=len-1;i>0;i--) {
if(digits[i]>=10) {
digits[i]%=10;
digits[i-1]+=1;
}else {
break;
}
}
if(digits[0]==10) {
int[] a=new int[len+1];
a[0]=1;
digits[0]=0;
for(i=0;i<len;i++) {
a[i+1]=digits[i];
}
return a;
}
return digits;
}
2.二进制加法
/**
*给定两个二进制字符串,返回他们的和(用二进制表示)。
* 输入为非空字符串且只包含数字 1 和 0。
*
* 示例 1:
* 输入: a = "11", b = "1"
* 输出: "100"
*
* 示例 2:
* 输入: a = "1010", b = "1011"
* 输出: "10101"
*/
遇到这道题我就想到了java中字符串转整型的方法和整型转二进制的方法,走起
public static String method1(String a, String b) {
return Integer.toBinaryString(Integer.parseInt(a,2)+Integer.parseInt(b,2));
}
可想而知,这种方法在数值较大时是无法运行的,整形的最大到2的31次方减一,一旦超出这个数值就会发生转换错误。
我们要想一种通用的算法,可以采用这样的方式,因为要对应位置相加,所以可以把两个String倒着取数运算,运算时因为'1'对应的ascall码为49,‘0’对应的是48,所以两者相减刚好得到正确的值。把每次运算的值存入StringBuffer,处理最后的进位,因为是追加的结果,所以最后要反转一下String。
public static String method2(String a, String b) {
StringBuilder sb = new StringBuilder();
int i = a.length() - 1, j = b.length() -1, carry = 0;
while (i >= 0 || j >= 0) {
int sum = carry;
if (j >= 0) sum += b.charAt(j--) - '0';
if (i >= 0) sum += a.charAt(i--) - '0';
sb.append(sum % 2);
carry = sum / 2;
}
if (carry != 0) sb.append(carry);
return sb.reverse().toString();
}
判断可以用三目运算符替代,最后的进位操作可以合并到循环中去,如果每次都是把加和结果拼接到字符串前面最后的字符串反转也可以省去
public static String method3(String a, String b) {
String ret = "";
int len_a = a.length() - 1;
int len_b = b.length() - 1;
int c = 0;
while (len_a >= 0 || len_b >= 0 || c == 1)
{
c += (len_a >= 0 ? a.charAt(len_a--) - '0' : 0);
c += (len_b >= 0 ? b.charAt(len_b--) - '0' : 0);
ret = (char)(c % 2 + '0')+ret;
c /= 2;
}
return ret;
}
3.平方根
/**
* 实现 int sqrt(int x) 函数。
* 计算并返回 x 的平方根,其中 x 是非负整数。
* 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
*
* 示例 1:
* 输入: 4
* 输出: 2
*
* 示例 2:
* 输入: 8
* 输出: 2
* 说明: 8 的平方根是 2.82842...,由于返回类型是整数,小数部分将被舍去。
*/
看到这道题,第一时间想到了Math.sqrt()方法,试了试果然可行,它的内部实现则是调用的C方法,无法查询到具体实现,但题目中只要求求出近似值整数,这为我们的算法实现减少了很多难度,找一个数的近似平方根的过程其实就是在一个范围内找一个平方近似等于目标值的数,可以采用二分查找计算。不断比较,找到了就返回,找不到就返回最后值中较小的那一个,如果最后剩一个值直接返回,剩两个就两数加和除以2,因为最后两个一定是相连的,除以2得到的结果就是较小的那个值。
public static int method2(int x) {
if (x<0)return 0;
if (x<2)return x;
int low=0,high=x/2;
while (low <= high) {
long mid = (low + high) / 2;
if (mid * mid > x) {
high = (int) (mid - 1);
} else if (mid * mid < x) {
low = (int) (mid + 1);
} else {
return (int) mid;
}
}
return high;
}
4.爬楼梯
/**
* 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
* 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
* 注意:给定 n 是一个正整数。
*
* 示例 1:
* 输入: 2
* 输出: 2
* 解释: 有两种方法可以爬到楼顶。
* 1. 1 阶 + 1 阶
* 2. 2 阶
*
* 示例 2:
* 输入: 3
* 输出: 3
* 解释: 有三种方法可以爬到楼顶。
* 1. 1 阶 + 1 阶 + 1 阶
* 2. 1 阶 + 2 阶
* 3. 2 阶 + 1 阶
*/
这道题你可以这么想,第一种办法就是全走1,还有就是走一个2,其它都是1,那就是的形式,最多可以走n/2个2阶,比如说5个台阶就是,如此迭代。计算C的时候就是,这里有需要注意的一点就是经常提到了int的极限问题,分子非常容易突破int的极限,我们可以把它们存入数组,然后从后往前把分子分母相同的部分置为1,这样可以减少数值的大小。
public static int method1(int n) {
int nums=1;
int half=n/2;
int i=1;
while (i<=half){
nums+=getCxy(i,n-i);
i++;
}
return nums;
}
public static int getCxy(int x,int y){
int[] highs=new int[x];
int[] lows=new int[x];
long high=1,low=1;
int x2=x;
while (x>=1){
highs[x-1]=y--;
x--;
}
while (x2>=1){
lows[x2-1]=x2;
x2--;
}
for (int i=highs.length-1;i>=0;i--){
if (highs[i]==lows[i]){
highs[i]=1;
lows[i]=1;
}else {
high*=highs[i];
low*=lows[i];
}
}
return (int)(high/low);
}
如果你仔细算过前7,8位的数字,你会发现这是一个斐波那契数列,???,想了半天没想明白,但是代码很好写。谁明白可以帮忙讲一下
private static int method2(int n){
int x1=1, x2=1, c=0;
for (int i=0;i<n-1;i++){
c=x2;
x2=x1+x2;
x1=c;
}
return x2;
}