Leetcode(easy Bit)
Leetcode(easy Bit)
leetcode位運算的簡單的題目總結
136 只出現一次的數字
題目:給定一個非空整數陣列,除了某一個元素只出現一次之外,其餘每個元素均出現了兩次,找出那個只出現一次的元素。
說明:你的演算法應該具有線性時間複雜度,而且儘量不使用額外空間
解題思路:用到了位運算中的異或操作,兩個相同的數字異或結果是0,數字與0異或的結果還是這個數字,並且異或操作滿足交換律與結合律。
時間複雜度O(n) 因為對nums進行了一次的遍歷
空間複雜度O(1) 沒有佔用額外的記憶體空間
class Solution{ public int singleNumber(int[] nums){ if(nums.length==0||nums==null) return 0; int res = nums[0]; for(int i = 1;i<nums.length;i++) res^=nums[i]; return res; } }
169 多數元素
題目:給定一個大小為n的陣列,找到其中的多數元素,多數元素指的是在陣列中出現次數嚴格大於一半的元素。
保證陣列是非空的,並且給定的陣列總是存在多數元素
解題思路1:投票 時間複雜度O(n) ,空間複雜度O(1)
解題思路2: 排序 時間複雜度O( n * log n) ,空間複雜度O(1)
解題思路3: Hash表 時間複雜度O(n) ,空間複雜度O(n)
解題思路4:分治演算法 時間複雜度O(n * log n) ,空間複雜度O(log n)
解題思路5: 位運算 時間複雜度O(n) ,空間複雜度O(1)
// 投票演算法 class Solution{ public int majorElement(int[] nums){ int vote = 0; int res = 0; for(int i = 0;i<nums.length;i++){ if(vote == 0){ res = nums[i]; vote++; }else{ if(res == nums[i]) vote++; else vote--; } } return res; } }
// 分治演算法 class Solution{ private int countInRange(int[] nums,int num,int lo,int hi){ int count = 0; for(int i = lo;i<=hi;i++) if(nums[i] == num) count++; return count; } private int majorityElementRec(int[] nums,int lo,int hi){ // base case : the only element in an array of size 1 is the majority element if(lo == hi) return nums[lo]; // recurse on left and right halves of this slice int mid = (hi-lo)/2+lo; int left = majorityElementRec(nums,lo,mid); int right = majorityElementRec(nums,mid+1,hi); // if the two halves agree on the majority element return it if(left == right) return left; // otherwise count each element and return the winner int leftCount = countInRange(nums,left,lo,hi); int rightCount = countInRange(nums,right,lo,hi); return leftCount>rightCount?left:right; } public int majorElement(int[] nums){ return majorityElementRec(nums,0,nums.length-1); } }
//位運算:思路由於眾數出現的次數大於n/2,那麼眾數對應的二進位制每一個為1的位數出現的次數一定大於n/2
class Solution{
public int majorElement(int nums){
int result = 0;
int k = nums.length>>1;
for(int i = 0;i<32;i++){
// count 用於記錄將數字轉換成為二進位制數之後每一位對應到陣列中數字出現1的數量
int count = 0;
for(int num:nums){
count+=num>>i&1;
if(count>k){
result+=1<i;
break;
}
}
}
return result;
}
}
190 顛倒二進位制位
Waring:在Java語言中,是沒有無符號整數型別的,在JAVA中所有的整數型別都是有符號的整數型別。
題目:顛倒給定的32位無符號整數的二進位制位
解題思路:
class Solution{
// you need treat n as unsigned value
public int reverseBits(int n){
int result = 0;
for(int i = 0;i<=32;i++){
// 將給定的二進位制數,由低到高位依次取出
int tmp = n>>i;
tmp = tmp&1;
// 反轉,右移31-i位
tmp=tmp<<(31-i);
// 更新result
result|=tmp;
}
return result;
}
}
231 2的冪
題目 給定一個整數,編寫一個函式來判斷他是否是2的冪次方
解題思路1 : 位運算 如果一個整數是2的冪次方,那麼他的32位二進位制表示只能出現一個1,並且n不能是負數 時間複雜度O(1) 空間複雜度O(1)
解題思路2: 連續除法 判斷餘數 時間複雜度O(log n) 空間複雜度O(1)
// 連續除法
class Solution{
public boolean isPowerOfTwo(int n){
if(n==0) return false;
while(n%2==0) n/=2;
return n==1;
}
}
// 位運算
class Solution{
public boolean isPowerOfTwo(int n){
return n>0 && (n&(n-1)) == 0;
}
}
268 丟失的數字
題目:給定一個包含[0,n]中n個數的陣列nums,找出這個範圍內沒有出現在陣列中的元素
解題思路:異或
class Solution{
public int missingNumber(int[] nums){
int res = 0;
for(int i = 1;i<nums.length+1;i++) res^=i;
for(int num:nums) res^=num;
return res;
}
}
342 4的冪
題目:給定一個整數(32位有符號整數) 編寫一個函式用來判斷他是否是4的冪次方
解題思路:位運算,要清楚4的冪次方在二進位制表示中的特點 二進位制表示有以下特點:只有一個1,且1的位置在偶數位置上 判斷是否在偶數位置上,只需要與全部在奇數位置上的數字進行與運算,判斷其是否為0
奇數位置全部是1,且偶數位置都是0的數字是0xaaaaaaaa(16進位制)
偶數位置全部是0,且奇數位置全部都是1的陣列是ox55555555(16進位制)
class Solution{
public boolean isPowerOfFour(int num){
return (num>0) && ((num&(num-1))==0) && ((num & 0xaaaaaaaa) == 0);
}
}
371 兩整數之和
題目要求:不使用運算子+或者- 計算兩整數之和
解題思路 分析進位與數值位 a+b的進位為(a&b)<<1 ,a+b的數值位為 a^b 5+7 = 12 數值位為2 進位是10
5:101 7:111 ,,,101^111 = 010 = 2,,,,101&111<<1 = 1010,,,, 1010 ^ 010 = 1000 ,,,, 1010&010<<1 = 100
class Solution{
public int getSum(int a,int b){
// 結束條件:進位為0
while(b!=0){
// 計算數值位
int temp = a^b;
// 計算進位
b = (a&b)<<1;
a = temp;
}
return a;
}
}
389 找不同
題目:給定兩個字串s,t。其中t是s新增一個字元得到的 找到這個新增的字元
解題思路:異或
class Solution{
public char findTheDifference(String s ,String t){
char res = 0;
int lens = s.length();
for(int i = 0;i<lens;i++) res^=s.charAt(i)^t.chatAt(i);
res^=t.charAt(lens);
return res;
}
}
401 二進位制手錶
這個題我認為學習的內容在於瞭解到了Java的方法bitCount()用於計算一個數字的二進位制數字的1的個數
class Solution{
public List<String> readBinaryWatch(int num){
List<String> times = new ArrayList<>();
for(int h = 0;h<12;h++) for(int m = 0;m<60;m++) if(Integer.bitCount(h) + Integer.bitCount(m) == num) times.add(String.format("%d:%02d",h,m));
}
}
405 數字轉換成為16進位制數字
題目:給定一個整數,編寫一個演算法將這個整數轉換成為16進位制數
解題思路:利用位運算,一次取後面四位,然後對照16進位制換算陣列,進行換算,無符號右移4位直到num=0
class Solution{
public String toHex(int num){
char[] hex = "0123456789abcdef".toCharArray();
String s = new String();
while(num!=0){
int end = num&15;
s = hex[end]+s;
num>>>=4;
}
if(s.length()==0) s = "0";
return s;
}
}
461 漢明距離
題目:兩個整數之間的漢明距離指的是這兩個數字對應的二進位制位不同位置的數目。
解題思路:首先兩者異或 不同數字的異或結果為1,然後再去計算異或結果中1的位數。
class Solution{
public int hammingDistance(int x,int y){
int xor = x^y;
int res = 0;
while(xor!=0){
res++;
xor&=(xor-1);
}
return res;
}
}
476 數字的補數
題目:給定一個正整數,輸出他的補數。補數是對該數的二進位制表示取反
解題思路:創造一個與給定數二進位制位數相同的全部是1 的新的二進位制數,然後用這個全部為1的二進位制數與原有的數進行異或。異或操作會把原來是1的變為0,原來是0的變為1。
class Solution{
public int findComplement(int num){
int tmp = 1;
while(tmp<num){
tmp<<=1;
tmp+=1;
}
return tmp^num;
}
}
693 交替位二進位制數
題目:給定一個整數,檢查他是否為交替二進位制數。換句話說就是他的二進位制數相鄰的兩個位數永遠不想等
解題思路:每次取二進位制數的最後一位,並儲存上次取的二進位制數,判斷二者是否相等,不想等的話,將數字無符號右移。
class Soluton{
public boolean hasAlternatingBits(int n){
int pre = n&1;
n>>>=1;
while(n!=0){
if((n&1)==pre) return false;
pre = n&1;
n>>>=1;
}
return true;
}
}
762 二進位制表示中質數個計算置位
1290 二進位制連結串列轉整數
給一個單鏈表的引用節點,連結串列中的節點值不是1就是0,請返回該連結串列的十進位制數字。
class Solution{
public int getDecimalValue(ListNode head){
int flag = 0;
int res = 0;
int len = 0;
ListNode pre = head;
while(pre != null){
len++;
pre=pre.next;
}
pre =head;
while(pre!=null){
if(pre.val == 1) res+=Mtah.pow(2,len-flag-1);
flag++;
pre = pre.next;
}
return res;
}
}
1342 將數字變成0的操作次數
class Solution{
public int numberOfSteps(int num){
int res = 0;
while(num!=0){
if(num%2==1){
res++;
num-=1
}else{
res++;
num/=2;
}
}
return res;
}
}
1356 根據數字二進位制下1的數目排序
class Solution{
public int[] sortByBits(int[] arr){
Map<Integer,List<Integer>> map = new TreeMap<>();
int[] res = new int[arr.length];
for(int num:arr){
int temp = helper(num);
if(!map.cnotainsKey(temp)){
map.put(temp,new LinkedList<>());
map.get(temp).add(sum);
}
else{
map.get(temp).add(num);
}
}
int i = 0;
for(int key:map.keySet()){
Collections.sort(map.get(key));
for(int num:map.get(key)){
res[i++] = num;
}
}
return res;
}
public int helper(int num){
int res = 0;
while(num!=0){
res++;
num&=(num-1);
}
return res;
}
}
1486 陣列異或操作
沒有意思的一題
Offer 15 二進位制中1的個數
同上
Offer 39 陣列中出現次數超過一半的數字
同上
面試題 05.01 插入
class Solution{
// N = 1024 10000000000 M = 19 10011 i=2 j=6 res = 1100 100001001100
public int insertBits(int N,int M,int i ,int j){
int mask = (1<<(j-i+1)-1)<<i; // i = 2 j = 6 : 100000 -> 011111 -> 1111100
mask~=mask; // 0000011
N&=mask; // 10001111100
M=M<<i; // 1001100
return M|N; // 100001001100
}
}
面試題 05.03 翻轉數位
題目:給定一個32位整數num,你可以將一個數從0變為1,請編寫一個程式,找出你能夠獲得的最長的一串1的長度
class Solution{
public int reverseBits(int num){
if(num == -1) return 32;
String s = Integer.toBinaryString(num);
String[] arr = s.split("0");
if(arr.length < 1) return arr.length+1;
int max = arr[0].length();
int res = max+1;
for(int i = 1;i<arr.length;i++){
if(arr[i-1].length() + arr[i].length() > max){
max = arr[i-1].length()+arr[i].length();
res=max+1;
}
}
return res;
}
}
面試題 05.06 整數轉換
題目:編寫一個方法,確定需要改變幾個位才能將整數A變成整數B
class Solution{
public int convertInteger(int A,int B){
int xor = A^B;
int res = 0;
while(xor!=0){
res++;
xor&=(xor-1);
}
return res;
}
}
面試題 05.07 配對交換
題目:編寫一個方法,交換某個整數的奇數位與偶數位
class Solution{
public int exchangeBits(int num){
int odd = num&0x55555555;
int even = num&0xaaaaaaaa;
odd = odd<<1;
even = even>>>1;
return odd|even;
}
}
面試題 16.07 最大數值
題目:編寫一個方法,找出兩個數字a和b中最大的哪一個。不能使用if-else或者其他比較運算子
class Solution{
public int maximum(int a,int b){
long c = a;
long b = b;
int res = (int)(Math.abc(c-d) + c + d/2);
return res;
}
}
面試題 17.01 不用加號的加法
同上
面試題 17.04 消失的數字
同上
面試題 17.10 主要元素
同上