應用技巧1:x&(x-1)【消除x(二進制)最後一位1】html
應用技巧2:<<左移【除2】java
應用技巧3:>>右移【×2】結合&1【判斷最後一位是否爲1】ios
def checkPowerof2(x): return x>0 and x&(x-1)==0
def isFour(n): m=1 while m<n: m=m<<2 return m==n
題目:數組
You are given an array A1,A2...AN. You have to tell how many pairs (i, j) exist such that 1 ≤ i < j ≤ N and Ai XOR Aj is odd.加密
思路:判斷列表數據中最後一位是0的個數和1的個數,二者相乘即爲結果。spa
代碼:.net
T = int(input()) for i in range(T): N = int(input()) res = 0 arr = list(map(int,input().split())) odd , even = 0 , 0 for i in range(N): if arr[i]&1: odd += 1 else: even += 1 print(odd * even)
// Non Recursion class Solution { /** * @param S: A set of numbers. * @return: A list of lists. All valid subsets. */ public List<ArrayList<Integer>> subsets(int[] nums) { List<ArrayList<Integer>> result = new ArrayList<List<Integer>>(); int n = nums.length; Arrays.sort(nums); // 1 << n is 2^n // each subset equals to an binary integer between 0 .. 2^n - 1 // 0 -> 000 -> [] // 1 -> 001 -> [1] // 2 -> 010 -> [2] // .. // 7 -> 111 -> [1,2,3] for (int i = 0; i < (1 << n); i++) { List<Integer> subset = new ArrayList<Integer>(); for (int j = 0; j < n; j++) { // check whether the jth digit in i's binary representation is 1 if ((i & (1 << j)) != 0) { subset.add(nums[j]); } } result.add(subset); } return result; } }
java代碼:3d
public class Solution { public int singleNumber(int[] nums) { int ones = 0, twos = 0; for(int i = 0; i < nums.length; i++){ ones = (ones ^ nums[i]) & ~twos; twos = (twos ^ nums[i]) & ~ones; } return ones; } }
public class Solution { public int[] singleNumber(int[] nums) { //用於記錄,區分「兩個」數組 int diff = 0; for(int i = 0; i < nums.length; i ++) { diff ^= nums[i]; } //取最後一位1 //先介紹一下原碼,反碼和補碼 //原碼,就是其二進制表示(注意,有一位符號位) //反碼,正數的反碼就是原碼,負數的反碼是符號位不變,其他位取反 //補碼,正數的補碼就是原碼,負數的補碼是反碼+1 //在機器中都是採用補碼形式存 //diff & (-diff)就是取diff的最後一位1的位置 diff &= -diff; int[] rets = {0, 0}; for(int i = 0; i < nums.length; i ++) { //分屬兩個「不一樣」的數組 if ((nums[i] & diff) == 0) { rets[0] ^= nums[i]; } else { rets[1] ^= nums[i]; } } return rets; } }
c = a-b,sign(c),sign(a),sign(b):表示a,b,c的正負
sign(a) == sign(b):則不會溢出,sign(c)>0則返回a,不然返回b
sign(a) != sign(b):返回sign(a)、sign(b)大的一個。
給定兩個32位整數a,b,可正,可負,可0,不能使用算術運算符,分別實現a和b的加減乘除運算。
兩個運算【異或】以及【&加左移<<】。
不考慮進位:a^b
僅考慮進位:(a&b)<<1
將上面兩個不斷相加直到沒有進位產生爲最終結果。
代碼:
def add(a,b): sum = a while b!=0: sum = a^b b = (a&b)<<1 a = sum return sum a = 19 b = 12 add(a,b)
#加法 def add(a,b): sum = a while b!=0: sum = a^b b = (a&b)<<1 a = sum return sum #減法 #取反加1得-b def negNum(b): return add(~b,1) #a+(-b) def minus(a,b): return add(a,negNum(b)) a = 19 b = 12 minus(a,b)
代碼:
代碼:
給定一個32位整數n,可爲0,可爲正,也可爲負,返回該整數二進制表達中1的個數。
給定一個整型數組arr,其中只有一個數出現了奇數次,其餘的數都出現了偶數次i,打印這個數。
進階問題:有兩個數出現了奇數次,其餘的數都出現了偶數次,打印這兩個數。
進階思路:先將數組全部數字異或,最後結果就是兩個出現一次的數字相互異或的結果,再將這兩個數分別分在兩個數組中進行異或。
http://www.javashuo.com/article/p-kltdyjse-do.html
給定一個整型數組arr和一個大於1的整數k。已知arr中只有1個數出現了1次,其餘的數都出現了k次,請返回只出現了1次的數。
定律:k個相同的k進制無進位相加的結果爲0.
例如: 兩個相同的2進制 100110101
100110101
無進位相加 結果 0000000
解法:把數組中的每一個元素當作k進制 , 全部元素相加後獲得的k進制結果就是 那個只出現一次的數,而後轉成相應的十進制,得解。
詳細解釋:
一個重要結論:
解該題:
def onceNum(arr,k): eO = [0] * 32 for i in range(len(arr)): setExclusiveOr(eO,arr[i],k) res = getNumFromKSysNum(eO,k) return res #得到全部的K進制無進位加和 def setExclusiveOr(eO,value,k): curKSysNum = getKSysNumFromNum(value,k) for i in range(len(eO)): eO[i] = (eO[i] + curKSysNum[i]) % k #得到K進制,res返回的是k進制 def getKSysNumFromNum(value,k): res = [0] * 32 index = 0 while value != 0: res[index] = value % k index += 1 value = value // k return res
#將結果的那個K進制數轉成十進制數輸出
def getNumFromKSysNum(eO,k): res = 0 for i in range(len(eO) - 1,-1,-1): res = res * k + eO[i] return res arr = [1,1,1,2,2,2,4] k = 3 onceNum(arr,k)
給定一個double類型的浮點數base和int類型的整數exponent。求base的exponent次方。
寫出指數的二進制表達,例如13表達爲二進制1101。
經過&1和>>1來逐位讀取1101,爲1時將該位表明的乘數累乘到最終結果。
舉例:10^1101 = 10^0001*10^0100*10^1000
def Power(self, base, exponent): # write code here #return math.pow(base,exponent) if base == 0 : return 0 if exponent == 0: return 1 elif exponent < 0: n = -exponent else: n = exponent res = 1 cur = base while n: if (n&1) == 1: res *= cur cur *= cur n = n >> 1 return res if exponent > 0 else (1/res)
【1 ,1,2,3,3】--->【1,1,10,11,11】---> sum(1,1,10,11,11) --->1010【兩個1,答案爲2】
題目描述:小Q十分富有,擁有很是多的硬幣,小Q擁有的硬幣是有規律的,對於全部的非負整數K,小Q剛好各有兩個面值爲2^k的硬幣,全部小Q擁有的硬幣就是1,1,2,2,4,4,8,8.....小Q有一天去商店購買東西須要支付n元錢,小Q想知道有多少種方案從他擁有的硬幣中選取一些拼湊起來剛好是n元(若是兩種方案某個面值的硬幣選取的個數不同就考慮爲不同的方案)
輸入:
輸入包括一個整數n(1<=n<=10^18),表示小Q須要支付多少錢,注意n的範圍
輸出:
輸出一個整數,表示小Q能夠拼湊出n元錢的方案數
樣例輸入:6
樣例輸出:3 (例如4+2, 4+1+1, 2+2+1+1)
一個很秒的思路:https://blog.csdn.net/xiaoquantouer/article/details/78076764
將硬幣分爲兩份:1,2,4,8,16,... 和1,2,4,8,16,...
組成兩個數值爲a, b的兩個數,他們的和是a+b=n;
a在第一份中只有可能有一種組合方式(採用二進制的思想,任何一個數均可以由若干個2^i的數相加的和組成),而b = n-a也只會有一種組合形式。
將a和b使用二進制表示,舉個例子n=11,有a=101, b=110這種組合,即a = 1+0+4=5,b=0+2+4=6。可是注意到會有重複的狀況,好比111+100和101+110本質上是同一種組合方法,因此須要將二個數作二進制異或而後去重。
代碼:
#include <iostream> #include<set> using namespace std; int main() { int n; while(cin>>n){ set<int> countset; for(int i=1;i<=n/2;i++){ int result =i^(n-i); countset.insert(result); } cout<<countset.size()<<endl; } return 0; }