算法——數(shù)值運(yùn)算

關(guān)于二進(jìn)制數(shù)

求二進(jìn)制數(shù)1的個(gè)數(shù):
知識(shí)點(diǎn):在計(jì)算機(jī)中所有數(shù)據(jù)都是二進(jìn)制類型的,所以不用特意的去轉(zhuǎn)換。
n & (n - 1),會(huì)把該整數(shù)n最右邊一個(gè)1變成0。

/*
一個(gè)二進(jìn)制數(shù)1100,從右邊數(shù)起第三位是處于最右邊的一個(gè)1。減去1后,第三位變成0,它后面的兩位0變成了1,
        而前面的1保持不變,因此得到的結(jié)果是1011.我們發(fā)現(xiàn)減1的結(jié)果是把最右邊的一個(gè)1開始的所有位都取反了。
        這個(gè)時(shí)候如果我們?cè)侔言瓉淼恼麛?shù)和減去1之后的結(jié)果做與運(yùn)算,從原來整數(shù)最右邊一個(gè)1那一位開始所有位都會(huì)變成0。
        如1100&1011=1000.也就是說,把一個(gè)整數(shù)減去1,再和原整數(shù)做與運(yùn)算,會(huì)把該整數(shù)最右邊一個(gè)1變成0.
        那么一個(gè)整數(shù)的二進(jìn)制有多少個(gè)1,就可以進(jìn)行多少次這樣的操作。
*/
    public int NumberOf1(int n) {
        int count = 0;
        while(n!= 0){
            count++;
            n = n & (n - 1);
            }
        return count; 
    }

如果一個(gè)整數(shù)不為0,那么這個(gè)整數(shù)至少有一位是1。如果我們把這個(gè)整數(shù)減1,那么原來處在整數(shù)最右邊的1就會(huì)變?yōu)?,原來在1后面的所有的0都會(huì)變成1(如果最右邊的1后面還有0的話)。其余所有位將不會(huì)受到影響。

關(guān)于數(shù)值的冪次運(yùn)算

有符號(hào)左移(<<)向左移動(dòng)n位,就相當(dāng)于乘以2^n。
帶符號(hào)右移(>>)如果該數(shù)為正,則高位補(bǔ)0,若為負(fù)數(shù),則高位補(bǔ)1。右移一位相當(dāng)于除2,右移n位相當(dāng)于除以2的n次方。
不帶符號(hào)右移>>>表示不帶符號(hào)向右移動(dòng)二進(jìn)制數(shù),移動(dòng)后前面統(tǒng)統(tǒng)補(bǔ)0。
如 -12 的二進(jìn)制為:1111 1111 1111 1111 1111 1111 1111 0100;
-12 >> 3 即帶符號(hào)右移3位,結(jié)果是:1111 1111 1111 1111 1111 1111 1111 1110,十進(jìn)制為: -2;
-12 >>> 3 就是右移三位,前面補(bǔ)零,為:0001 1111 1111 1111 1111 1111 1111 1110,十進(jìn)制為:536870910。
給定一個(gè)double類型的浮點(diǎn)數(shù)base和int類型的整數(shù)exponent。求base的exponent次方。
(快速冪運(yùn)算)

        public double Power1(double base, int n) {
            double res = 1,curr = base;
            int exponent;
            if(n>0){
                exponent = n;
            }else if(n<0){
                if(base==0)
                    throw new RuntimeException("分母不能為0"); 
                exponent = -n;
            }else{// n==0
                return 1;// 0的0次方
            }
            while(exponent!=0){
                if((exponent&1)==1)
                    res*=curr;//當(dāng)指數(shù)為1時(shí)前面的結(jié)果在乘以這個(gè)curr
                curr*=curr;// 每一次循環(huán)底數(shù)自己相乘,翻倍 a,a^2,a^4,a^8,a^16.....
                exponent>>=1;// 右移一位
            }
            return n>=0?res:(1/res);       
        }

思路:

  • 1.全面考察指數(shù)的正負(fù)、底數(shù)是否為零等情況。
  • 2.寫出指數(shù)的二進(jìn)制表達(dá),例如13表達(dá)為二進(jìn)制1101。
  • 3.舉例:10^1101 = (10^0001)* (10^0100) *(10^1000)。
  • 4.通過&1和>>1來逐位讀取1101,為1時(shí)將該位代表的乘數(shù)累乘到最終結(jié)果。


    圖片.png

補(bǔ)充:

int mid = (x+y)>>1;相當(dāng)于(x+y)/2

寫一個(gè)函數(shù),求兩個(gè)整數(shù)之和。

要求在函數(shù)體內(nèi)不得使用+、-、*、/四則運(yùn)算符號(hào)。

例:求a+b。
思路:異或^是無進(jìn)位加法,與&操作獲得進(jìn)位。
a^b是當(dāng)a+b計(jì)算時(shí)沒有進(jìn)位情況下的結(jié)果

我們先來觀察下位運(yùn)算中的兩數(shù)加法,其實(shí)來來回回就只有下面這四種:

0 + 0 = 0
0 + 1 = 1
1 + 0 = 1
1 + 1 = 0(進(jìn)位 1)
就是相同位為 0,不同位為 1 的異或運(yùn)算結(jié)果

異或和與運(yùn)算操作
在位運(yùn)算操作中,異或的一個(gè)重要特性是無進(jìn)位加法。

a = 5 = 0101
b = 4 = 0100

a ^ b 如下:

0 1 0 1
0 1 0 0
----------
0 0 0 1
a ^ b 得到了一個(gè)無進(jìn)位加法結(jié)果,如果要得到 a + b 的最終值,我們還要找到進(jìn)位的數(shù),把這二者相加。
在位運(yùn)算中,我們可以使用與操作獲得進(jìn)位:

a = 5 = 0101
b = 4 = 0100

a & b 如下:

0 1 0 1
0 1 0 0
-------
0 1 0 0
由計(jì)算結(jié)果可見,0100 并不是我們想要的進(jìn)位,1 + 1 所獲得的進(jìn)位應(yīng)該要放置在它的更高位,即左側(cè)位上,因此我們還要把 0100左移一位,才是我們所要的進(jìn)位結(jié)果。

作者:jalan鏈接:https://leetcode-cn.com/problems/two-sum/solution/wei-yun-suan-xiang-jie-yi-ji-zai-python-zhong-xu-y/

        public int Add(int num1,int num2) {
            int a=num1^num2;
            int b=num1&num2;
            b=b<<1;
            int count=0;
            while(b!=0){
                int temp=a;
                a=a^b;
                b=temp&b;
                b=b<<1;
            }
            return a;
        }

一個(gè)整型數(shù)組里除了兩個(gè)數(shù)字之外,其他的數(shù)字都出現(xiàn)了兩次。請(qǐng)寫程序找出這兩個(gè)只出現(xiàn)一次的數(shù)字。


            int sum=0;
            num1[0]=0;
            num2[0]=0;
            
            for(int i=0;i<array.length;i++){
                sum^=array[i];
            }
            int index=findFirstIndexOf1(sum);
            for(int i=0;i<array.length;i++){
                int temp=array[i];
                if((temp>>index&1)==1){
                    num1[0]^=array[i];
                    System.out.println("num1[0]="+num1[0]);
                }
                else{
                    num2[0]^=array[i];
                    System.out.println("num1[0]="+num2[0]);
                }
            }
        }
        public int findFirstIndexOf1(int t){
            int index=0;//1000 3
            while((t&1)==0&&t!=0){
                t=t>>1;
                index++;
            }
            return index;
        }

解釋:
概念:位運(yùn)算中異或的性質(zhì):兩個(gè)相同數(shù)字異或=0,一個(gè)數(shù)和0異或還是它本身。
鏈接:https://www.nowcoder.com/questionTerminal/e02fdb54d7524710a7d664d082bb7811

當(dāng)只有一個(gè)數(shù)出現(xiàn)一次時(shí),我們把數(shù)組中所有的數(shù),依次異或運(yùn)算,最后剩下的就是落單的數(shù),因?yàn)槌蓪?duì)兒出現(xiàn)的都抵消了。

依照這個(gè)思路,我們來看兩個(gè)數(shù)(我們假設(shè)是AB)出現(xiàn)一次的數(shù)組。我們首先還是先異或,剩下的數(shù)字肯定是A、B異或的結(jié)果,這個(gè)結(jié)果的二進(jìn)制中的1,表現(xiàn)的是A和B的不同的位。我們就取第一個(gè)1所在的位數(shù),假設(shè)是第3位,接著把原數(shù)組分成兩組,分組標(biāo)準(zhǔn)是第3位是否為1。如此,相同的數(shù)肯定在一個(gè)組,因?yàn)橄嗤瑪?shù)字所有位都相同,而不同的數(shù),肯定不在一組。然后把這兩個(gè)組按照最開始的思路,依次異或,剩余的兩個(gè)結(jié)果就是這兩個(gè)只出現(xiàn)一次的數(shù)字。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 為什么明明是工作餐,卻不讓去吃呢?
    書宸閱讀 135評(píng)論 0 0
  • 俗話說的好,人在江湖飄哪能不挨刀,既然沒有云白云山壯骨粉可以銷售那我就自己制造,沒有噴子的地方就沒有江湖。 經(jīng)常遇...
    DrPepper閱讀 382評(píng)論 1 2
  • 朋友妮繼被拖延工資后,一波未平,一波又起,上班一個(gè)月了,剛剛才拿到勞動(dòng)合同,翻看了一遍,立馬就覺得心情不好了。 原...
    仔仔小祖祖閱讀 141評(píng)論 1 0
  • 2月16號(hào),我接觸到《自控力》這本書,還沒開始讀的時(shí)候就萌生出一個(gè)小念頭,想挑戰(zhàn)一下自己的意志力,那時(shí)候我剛...
    6d5d4fe9fb6d閱讀 1,005評(píng)論 0 3
  • 總覺得這本書還沒讀完,仔細(xì)確認(rèn)幾次才接受真真的結(jié)束了。一個(gè)人因?yàn)閻矍槟転榱硪蝗俗龅胶畏N極致的地步?看完書我一直在思...
    鳳兒DuDu閱讀 243評(píng)論 0 3

友情鏈接更多精彩內(nèi)容