Unit 8 其他

Unit 8 其他

Q1:求一个数的整数次方
Q2:打印从1到N的所有整数
Q3:整数N中1出现的次数
Q4:整数序列中的第n个数字
Q5:丑数
Q6:0~n-1中缺失的数字
Q7:和为S的两个数字
Q8:和为S的连续正数序列
Q9:给定序列是否是顺子
Q10:求1+2+…+n
Q11:用位运算实现两数之和
Q12:不用新变量交换a、b的值
Q13:下一个排列
Q14:多线程依次打印1-100
Q15:求平方根
Q16:十进制、二进制互转问题

unit 8 Q1:求一个数的整数次方

剑指offer 16 Leetcode 50 难度:中等
重写Math.pow()函数
date:2019/12/11
思路:
其实这道题很考察边界情况的处理。
两种特殊情况:

  • 指数为0时,直接返回1
  • 底数为0、指数为负数时,造成除零异常。应返回0

正常情况(如下)

方法一:正常做法,有几次幂做几次乘积,时间复杂度O(N)

    //正常做法:O(N)
    public double power(double base,double exponent){
        //特殊情况1:指数为0
        if(exponent==0)
            return 1;
        //特殊情况2:底数为0且指数为负
        if(base==0&&exponent<0)
            return 0;
        //正常情况
        //指数为负的话,先正着算,最后再倒回来
        double exp=(exponent>0)?exponent:-exponent;
        double res=1;
        while(exp!=0){
            res=res*base;//累乘
            exp--;
        }
        res=(exponent>0)?res:1/res;
        return res;
    }

方法二:O(log2N)
对a求其32次方,可以理解为:a的16次方 * a的16次方;
而a的16次方可理解为:a的8次方 * a的8次方

总结一下:
e为偶数时,a ^ e=[a ^ (e/2)] * [a ^ (e/2)]
e为奇数时,a ^ e=[a ^ ((e-1)/2)] * [a ^ ((e-1)/2)] * a
特殊情况,e为1时,a^e=a
有斐波那契数列内味了。递归和循环两种我都实现了power2和power3

  • 递归实现
    //递归O(log2N)
    public double power2(double base,double exponent){
        //特殊情况1:指数为0
        if(exponent==0)
            return 1;
        //特殊情况2:底数为0且指数为负
        if(base==0&&exponent<0)
            return 0;
        double exp=(exponent>0)?exponent:-exponent;//进递归时exp必须为正
        double res=F(base,exp);//处理完各种情况后送入递归
        res=(exponent>0)?res:1/res;
        return res;
    }
    private double F(double base,double exp){
        if(exp==1)
            return base;
        if(exp%2==0)
            //偶数
            return F(base,exp/2)*F(base,exp/2);
        else
            //奇数
            return F(base,(exp-1)/2)*F(base,(exp-1)/2)*base;
    }
  • 循环实现
    public double power3(double base,double exponent){
        //特殊情况1:指数为0
        if(exponent==0)
            return 1;
        //特殊情况2:底数为0且指数为负
        if(base==0&&exponent<0)
            return 0;
        double exp=(exponent>0)?exponent:-exponent;//进去时exp必须为正

        double[] F=new double[(int)exp+1];//F[n],即base^n的数值、
        F[0]=1;
        //F[1]=base;
        for(int i=1;i<(int)exp+1;i++){
            if(i%2==0)
                //偶数
                F[i]=F[i/2]*F[i/2];
            else
                //奇数
                F[i]=F[(i-1)/2]*F[(i-1)/2]*base;
        }
        double res=F[(int)exp];
        res=(exponent>0)?res:1/res;
        return res;
    }

好像还能用位运算替代除法?对时间复杂度没影响。懒狗了

 

unit 8 Q2:打印从1到N的所有整数

剑指offer 17
date:2019/12/12
思路
考察大数的处理。可以用数组或者字符串处理大数,这里用数组实现。
实现
boolean increment(int[] number):对number数组做自加操作
1.设置退出机制。即不再进位(当前位置计算后<=9)时,自加操作停止,break
2.最高位计算后>9,溢出,设置isOverflow为false。print1toN里停止对其循环
3.只对最后一位加1。

    private boolean increment(int[] number){
        boolean isOverflow=false;//是否溢出
        int nCarry=0;//进位
        //从个位(数组最后一个)开始遍历
        for(int i=number.length-1;i>=0;i--){
            int nSum=number[i]+nCarry;
            //只对个位数加1
            if(i==number.length-1) nSum++;
            //更新number数组,做过加一后大于9了,超了,要进位
            if(nSum>9){
                if(i==0)
                    //已经是最后一位了,已溢出
                    isOverflow=true;
                else{
                    //没溢出就做进位操作
                    number[i]=nSum-10;
                    nCarry=1;
                }
            }else{
                //没超,不用进位,后面不用更新,所以可以停了
                number[i]=nSum;
                break;
            }
        }
        return isOverflow;
    }

void printArr(int[] number):跳过前面的0打印数组

    //打印数组
    private void printArr(int[] number){
        int n=number.length;
        int i=0;
        while(i<n&&number[i]==0) i++;//前面的0跳过
        while(i<n)
            System.out.print(number[i++]);
        System.out.println();
    }

void print1toN(int N):increment没返回true(即没溢出)之前,持续调用increment,自加,打印。

    public void print1toN(int N){
        if(N<1)
            System.out.println("输入的N<1,输入出错");
        int[] number=new int[N];
        while(!increment(number))
            printArr(number);
    }

increment感觉还需要优化,不太好记。

 

unit 8 Q3:整数N中1的出现次数

剑指offer 43 牛客链接 Leetcode 233 难度:困难
给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。
输入: 13
输出: 6
解释: 数字 1 出现在以下数字中: 1, 10, 11, 12, 13
date:2020/02/15
思想:
过于晦涩,写写方法吧。时间复杂度O(LogN)

设整数N的位数是k。例:该数是abcde

  • PART1:最高位的1出现个数
    如果最高位是1:除去最高位剩下的数+1 (bcde+1)
    如果最高位 > 1:10^(k-1) (10000)
  • PART2:(bcde+1)~(abcde)中1的出现次数
    =(最高位的数字) × \times ×(除去最高位后剩下的位数) × \times × 10^(k-2) (a × \times × 4 × \times × 1000)
  • PART3:1~(bcde)中1的出现次数
    递归解决

数N中数字1出现的个数=PART1+PART2+PART3

左神的解释:
在这里插入图片描述
在这里插入图片描述
代码:

    public int NumberOf1Between1AndN_Solution(int n) {
        if (n < 1)
            return 0;
        int len = getLenOfNum(n);
        if (len == 1)
            return 1;
        int tmp = (int) Math.pow(10, len - 1);
        int first = n / tmp;
        int firstOneNum = first == 1 ? n % tmp + 1 : tmp;//PART1
        int otherOneNUm = first * (len - 1) * (tmp / 10);//PART2
        return firstOneNum + otherOneNUm + NumberOf1Between1AndN_Solution(n % tmp);
    }
 
    private int getLenOfNum(int n) {
        int len = 0;
        while (n != 0) {
            len++;
            n /= 10;
        }
        return len;
    }

 

unit 8 Q4:整数序列中的第n个数字

在无限的整数序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, …中找到第 n 个数字。
剑指offer 44 Leetcode 400 难度:中等 (牛客上缺这道题)
date:2020/02/16
思想:

  • 1.先求出序列中第n个数字是m位数。前(m-1)位数所占之和存为beforeSum。
  • 2.第n个数字和前(m-1)位之差存为dif。
  • 3.可以通过差值dif和m位数,求出第n个数字落在哪个数字里(thisNum=10^(m-1)+dif/m)的第几位(dif%m)
  • 4.已知数字thisNum和d第几位dif%m以后,用getPart()获得确定位的值,返回之。
	//leetcode oj 上的通过版本
    public int findNthDigit(int n) {
        if (n<10) return n;
        long  beforeSum=0;//之前的1...(m-1)位数所占位数之和
        int m=0;//第n位是m位数
        while(beforeSum<n){
            m++;
            beforeSum=beforeSum+countM(m);
        }
        //出while循环,n积为m位数
        //前(m-1)位数所占位数为beforeSum-countM(m)
        beforeSum=beforeSum-countM(m);
        int dif=n-(int)beforeSum;//dif:n和前(m-1)位的插值
        int thisNum,res;
        if(dif%m==0){
            //没有余数
            //第n位数字落在了thisNum这个数里 
            //pow(10,m-1):第一个m位数
            thisNum=(int)Math.pow(10,m-1)+(int)(dif/m)-1;
            res=getPart(thisNum,m);
        }else{
            thisNum=(int)Math.pow(10,m-1)+(int)(dif/m);
            res=getPart(thisNum,dif%m);
        }
        //res=res-1;
        return res;
    }

    //m位数总占几位。如:3位数:100~999有900个数,则共占3*900=2700位
    private long countM(int m){
        if(m==1)
            return 9;
        long res=m*9*(long)Math.pow(10,m-1);
        return res;
    }

    //得到数num的第i位。1234的第三位是3
    private int getPart(int num,int i){
        int len=0,temp=num;
        while(true){
            temp=(int)temp/10;
            len++;
            if(temp==0)
                break;
        }
        int res=-1;
        //除len-(i-1)次后的余数。举个例子找规律即可
        for(int count=0;count<len-(i-1);count++){
            res=num%10;
            num=num/10;
        }
        return res;
    }

 

unit 8 Q5:丑数

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
剑指offer 49 牛客链接
date:2020/02/18
思路:
写在注释里头。
代码:

    public int GetUglyNumber_Solution(int index) {
        if(index<=0)
            return 0;
        int[] arr=new int[index];
        arr[0]=1;//1是第一个丑数
        //由于丑数一定是某个小的丑数*(2、3、5)所得。则遍历数组,每轮更新一个最大的丑数
        //该丑数是数组前面的丑数*2 or *3 or *5中最小值
        //设置T2,T3,T5的目的:
        //如T2:刚好到T2时,arr[T2]*2>max。这样下一轮找*2且比max大的数时,可以再T2的基础上找
        int T2=0,T3=0,T5=0;
        //int max2=0,max3=0,max5=0;
        for(int i=1;i<index;i++){
            int max=arr[i-1];//上一个是当前最大的丑数
            while(arr[T2]*2<=max) T2++;
            while(arr[T3]*3<=max) T3++;
            while(arr[T5]*5<=max) T5++;
            int newMax=getMin(arr[T2]*2,arr[T3]*3,arr[T5]*5);
            arr[i]=newMax;
        }
        return arr[index-1];
    }
    
    //比较三个数的大小
    int getMin(int a,int b,int c){
        int min_ab=(a<b)?a:b;
        int min=(min_ab<c)?min_ab:c;
        return min;
    }

 

unit 8 Q6:0~n-1中缺失的数字

剑指offer 53_2 Leetcode链接
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
示例 1:
输入: [0,1,3]
输出: 2

示例 2:
输入: [0,1,2,3,4,5,6,7,9]
输出: 8

date:2020/02/19
代码:

    //如果没缺失,arr[0]存0,arr[1]存1,..,arr[i]存i
    //找到第一个值与下标不匹配的数字,返回下标
    //用归并排序,时间复杂度O(log2n)
    public int missingNumber(int[] arr) {
        int low=0,high=arr.length-1;
        int mid=0;
        while(low<=high){
            mid=(low+high)/2;
            if(arr[mid]!=mid&&(mid-1<0||arr[mid-1]==mid-1))
                return mid;
            //还匹配着,向右走
            if(arr[mid]==mid)
                low=mid+1;
            //不匹配了,向左找
            if(arr[mid]!=mid)
                high=mid-1;
        }
        if(low==arr.length)
            return low;
        return -1;
    }

 

unit 8 Q7:和为S的两个数字

剑指offer Q57_1 牛客链接
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
date:2020/02/21
思路:
先排序。初值左边是small,右边是big。如果arr[small]和arr[big]的和<sum,small++;反之,big–
代码:

import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
    //先排序。左边是small,右边是big。如果和<sum,small++;反之,big--
    public ArrayList<Integer> FindNumbersWithSum(int [] arr,int sum) {
        ArrayList<Integer> res=new ArrayList<Integer>();
        Arrays.sort(arr);
        int small=0,big=arr.length-1;
        while(small<arr.length && big>=0){
            if(arr[small]+arr[big]<sum)
                small++;
            else if(arr[small]+arr[big]==sum){
                res.add(arr[small]);
                res.add(arr[big]);
                break;
            }
            else
                big--;
        }
        return res;
    }
}

 

unit 8 Q8:和为S的两个数字

剑指offer Q57_2 牛客链接
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
date:2020/02/21
思路:
与Q7思路相似。初值small=1,big=2;如果small~big的和大于S,small++,反之big++。终止条件small>S/2 或者 small>=big。
代码:

import java.util.ArrayList;
public class Solution {
    //如果small到big的和小于sum,big++;反之small--。因为最少两个数,small>sum/2停止
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
       int small=1,big=2;
       ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer> >();
       int total=small+big;
       while(small<=sum/2&&small<big){
           if(total<sum){
               big++;
               total+=big;
           }else if(total==sum){
               //该返回了
               ArrayList<Integer> success=new ArrayList<Integer>();
               for(int i=small;i<=big;i++)
                   success.add(i);
               res.add(success);
               //为了让滑动窗口动起来,small++
               total-=small;
               small++;
           }else{
               //total>sum
               total-=small;
               small++;
           }
       }
       return res;
    }
}

 

unit 8 Q9:给定序列是否是顺子

剑指offer 61 牛客链接
给定长度为5的乱序扑克牌序列,判断该序列是否是顺子。
0是癞子,补在任意想补的地方;
示例 1:
输入: [1,2,3,4,5] 输出: True
示例 2:
输入: [0,0,1,2,5] 输出: True

date:2020/02/23

思路:
1.0可以当癞子。所以遍历时0跳过。
2.max-min<5 (顺子1,2,3,4,5的最大差值是5)
3.除0意外没有重复的数字。(用数组实现。本质是空间换时间)

代码:

public class Solution {
    public boolean isContinuous(int [] numbers) {
        if(numbers==null||numbers.length!=5)
            return false;
        int min=14,max=-1;
        int[] isAppeared=new int[14];//大小王是癞子,表示为0,其他从1到13
        for(int i=0;i<numbers.length;i++){
            int cur=numbers[i];
            if(cur==0)
                continue;//大小王直接跳过。反正大小王啥牌都能顶
            //出现过
            if(isAppeared[cur]!=0)
                return false;//cur出现过两次,不是顺子
            isAppeared[cur]=1;//表示cur这个数出现过
            max=Math.max(max,cur);
            min=Math.min(min,cur);
            if(max-min>=5)
                return false;//差值大于5就不是顺子了
        }
        return true;
    }
}

 

unit 8 Q10:求1+2+…+n

剑指offer 64 Leetcode链接 难度:中等
求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
示例 1:
输入: n = 3 输出: 6
示例 2:
输入: n = 9 输出: 45

date:2020/02/24

思想:
利用 && 的短路特性。
A && B:
A 为 true,则返回表达式 B 的 bool 值
A 为 false,则直接返回 false

代码:

class Solution {
    public int sumNums(int n) {
        int res=n;
        //如果n<=0就停止累加,反之不断累加至res。
        //后面的>0为了保证后半部分是boolean值,没有实际意义
        boolean is1=(n>0)&&((res=n+sumNums(n-1))>0);
        return res;
    }
}

 

unit 8 Q11:用位运算实现两数之和

剑指offer 65 牛客链接
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
date:2020/02/25
思想:

首先看十进制是如何做的: 5+7=12,三步走
第一步:相加各位的值,不算进位,得到2。
第二步:计算进位值,得到10. 如果这一步的进位值为0,那么第一步得到的值就是最终结果。
第三步:重复上述两步,只是相加的值变成上述两步的得到的结果2和10,得到12。

同样我们可以用三步走的方式计算二进制值相加: 5-101,7-111
第一步:相加各位的值,不算进位,得到010,二进制每位相加就相当于各位做异或操作,101^111。
第二步:计算进位值,得到1010,相当于各位做与操作得到101,再向左移一位得到1010,(101&111)<<1。
第三步重复上述两步, 各位相加 010^1010=1000,进位值为100=(010&1010)<<1。
继续重复上述两步:1000^100 = 1100,进位值为0,跳出循环,1100为最终结果。

总结一下:

  1. 两个数异或:相当于每一位相加,而不考虑进位;
  2. 两个数相与,并左移一位:相当于求得进位;
  3. 将上述两步的结果相加

代码:

public class Solution {
    public int Add(int num1,int num2) {
        while(num2!=0){
            int sum=num1^num2;//逐位做异或运算,相当于不进位做加法
            int carry=(num1&num2)<<1;//逐位做与运算再左移(最后补0),相当于求得进位
            num1=sum;
            num2=carry;
        }
        return num1;
    }
}

 

unit 8 Q12:不用新变量交换a、b的值

剑指offer 65_2
date:2020/02/25

  • 异或法
//设原先的a、b分别为a0和b0
a = a^b;  //a做暂存
b = a^b;  // b=(a0^b0)^b0=a0
a = a^b;  // a=(a0^b0)^a0=b0
  • 加减法
//设原先的a、b分别为a0,b0
a = a + b;  //a暂存
b = a - b;  //b=(a0+b0)-b0=a0
a = a - b;  //a=(a0+b0)-b0=a0

 

unit 8 Q13:下一个排列

Leetcode 31 难度:中等 头条面试题

实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
例1:1,2,3 → 1,3,2
例2:3,2,1 → 1,2,3
例3:1,1,5 → 1,5,1

date:2020/03/05

做法:

  1. 从右至左找到第一对升序的a[i-1]和a[i]
    (如果数组降序,直接反转全部,返回)
  2. 在i~(len-1)中找到一个a[j],使a[j]是比a[i-1]大的数中最小的
  3. 交换a[i-1]和a[j]
  4. 反转数组的i~(len-1)部分

代码:

class Solution {
    public void nextPermutation(int[] nums) {
        //只有从左至右升序,交换后才会变成更大的序列;
        //如果从左至右降序,交换后只会变小,所以不交换。
        //1.从右至左找到第一对升序的a[i-1]和a[i]
        int len=nums.length;
        int i=len-1;
        for(;i>0;i--){
            //碰到升序就break
            if(nums[i]>nums[i-1])
                break;
        }
        //没找到,说明从左至右是逆序的。全部翻转即可
        if(i==0){
            reverse(nums,0,len-1);
        }else{
            //找到了a[i-1]<a[i]的一对
            //2.想要在i~(len-1)中找到一个a[j],使a[j]是比a[i-1]大的数中最小的
            //由于第一个for从右往左找的,i~(len-1)已经逆序,第一个比a[i-1]小的数就是a[j+1]
            int j=i-1;
            for(;j<len-1;j++){
                if(nums[j+1]<=nums[i-1])
                    break;
            }
            //3.交换a[i-1]和a[j]
            swap(nums,i-1,j);
            //4.反转数组的i~(len-1)部分
            reverse(nums,i,len-1);
        }
    }
    void reverse(int[] nums,int i,int j){
            while(i<j){
                swap(nums,i,j);
                i++;j--;
            }
    }
    void swap(int[] nums,int i,int j){
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }
}
unit 8 Q14:多线程依次打印1-100

date:2020/5/18
很爱作为面试真题

方法1:最简单
缺点:如果同一个线程一直抢到锁,而另一个线程一直没有拿到,就会导致线程做很多无谓的空转

import java.util.*;
class Solution {
    static int count = 1;//计数
    static final Object lock = new Object();//锁
    static final int TOTAL=100;//总数
    public static void main(String[] args){
            Thread thread1 = new Thread(){
                public void run(){
                    while (count <= 100) {
                        synchronized (lock) {
                        // 只处理奇数
                            if ((count % 2) == 1)
                                System.out.println("Thread1: " + count++);
                        }
                    }
                }
            };
            Thread thread2 = new Thread(){
                public void run() {
                    while (count <= 100) {
                        synchronized (lock) {
                            // 只处理偶数
                            if ((count % 2) == 0)
                                System.out.println("Thread2: " + count++);
                        }
                    }
                }
            };
            thread1.start();
            thread2.start();
    }
}

方法二:利用synchronized 互斥锁,Object.wait() 和 Object.notify() 进行组合

import java.util.*;
class Solution {
    static int count = 1;//计数
    static final Object lock = new Object();//锁
    static final int TOTAL=100;//总数
    public static void main(String[] args){

            Thread thread1 = new Thread(){
                public void run(){
                    while (count <= 100) {
                        synchronized (lock) {
                        // 只处理奇数
                            if ((count % 2) == 1)
                                System.out.println("Thread1: " + count++);
                            //偶数让出锁
                            else{
                                lock.notifyAll();//让出锁,让其他来竞争
                                try{
                                    lock.wait();//当前阻塞
                                }catch (InterruptedException e){
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            };
            Thread thread2 = new Thread(){
                public void run() {
                    while (count <= 100) {
                        synchronized (lock) {
                            // 只处理偶数
                            if ((count % 2) == 0)
                                System.out.println("Thread2: " + count++);
                            //奇数就让出锁
                            else{
                                lock.notifyAll();//让出锁,让其他来竞争
                                try{
                                    lock.wait();//当前阻塞
                                }catch(InterruptedException e){
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            };
            thread1.start();
            thread2.start();
    }
}


unit 8 Q15:求平方根

经典面试题;美团真题;Leetcode 69 难度:简单

实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

示例 1:
输入: 4
输出: 2

示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842…,由于返回类型是整数,小数部分将被舍去。

方法一:暴力查找

class Solution {
    //暴力查找
    public int mySqrt(int x) {
        for(long i=0;i<=x;++i){
            if(i*i<=x && (i+1)*(i+1)>x)
                return (int)i;
        }
        return -1;
    }
}

方法:二分查找

class Solution {
    //二分查找
    public int mySqrt(int x) {
        long left=0,right=x;//应付测试用例中的大数,用long
        while(left<=right){
            long mid=(left+right)/2;
            if(mid*mid<=x&&(mid+1)*(mid+1)>x)
                return (int)mid;
            //小了,向右
            if(mid*mid<x)
                left=mid+1;
            //大了,向左
            else
                right=mid-1;
        }
        return -1;
    }
}

如果题目要求四舍五入: 在退出条件上再做文章:
二分查找为例,退出条件可改为:

if(mid*mid<=x && (mid+1)*(mid+1)>x){
	float temp=(float)mid+0.5;//例:3 -> 3.5
	if(temp*temp > x)
		return (int)mid;//说明值夹在(mid,mid+0.5)之间,应该四舍
	else
		return (int)(mid+1);//五入
}
unit 8 Q16:十进制、二进制互转

Leetcode 1009、476 难度:简单
给定一个正整数,输出它的补数。补数是对该数的二进制表示取反。

示例 1:
输入: 5
输出: 2
解释: 5 的二进制表示为 101(没有前导零位),其补数为 010。所以你需要输出 2 。

示例 2:
输入: 1
输出: 0
解释: 1 的二进制表示为 1(没有前导零位),其补数为 0。所以你需要输出 0

思路:

  1. 十进制转二进制
  2. 对二进制取反
  3. 二进制转十进制

调包的做法

class Solution {
    public int bitwiseComplement(int N) {
        String binaryN=Integer.toBinaryString(N);//十进制转换二进制
        char[] binaryNChar=binaryN.toCharArray();
        String res="";
        for(int i=0;i<binaryNChar.length;++i){
            if(binaryNChar[i]=='1')
                res += '0';
            else
                res += '1';
        }
        return Integer.parseInt(res,2);//二进制再转换为十进制
    }
}

如果面试官要我自己实现十进制转二进制呢?

    //十进制转二进制(不调包)
    public int decimalToBinary(int N){
        ArrayList<Integer> yushuList=new ArrayList<Integer>();
        while(N!=0){
            int yushu=N%2;
            N=N/2;
            yushuList.add(yushu);
        }
        //反着取数
        long res=0;
        for(int i=yushuList.size()-1;i>=0;i--){
            int cur=yushuList.get(i);
            res = res*10 + cur;
        }
        return res;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值