Showing posts with label to-do-2. Show all posts
Showing posts with label to-do-2. Show all posts

Bit Hack Misc


http://blog.csdn.net/morewindows/article/details/7354571
变换符号只需要取反后加1即可
  1. int SignReversal(int a)  
  2. {  
  3.     return ~a + 1;  
  4. }  
求绝对值
  1. int my_abs(int a)  
  2. {  
  3.     int i = a >> 31;  
  4.     return i == 0 ? a : (~a + 1);  
  5. }  
对于任何数,与0异或都会保持不变,与-1即0xFFFFFFFF异或就相当于取反。因此,a与i异或后再减i(因为i为0或-1,所以减i即是要么加0要么加1)也可以得到绝对值。所以可以对上面代码优化下:
  1. int my_abs(int a)  
  2. {  
  3.     int i = a >> 31;  
  4.     return ((a ^ i) - i);  
三. 位操作与空间压缩
要压缩素数表的空间占用,可以使用位操作

http://segmentfault.com/a/1190000003789802
> 不用额外的变量实现两个数字互换。
def swap(num_1, num_2):
    num_1 ^= num_2
    num_2 ^= num_1
    num_1 ^= num_2
    return num_1, num_2
证明很简单,我们只需要明白异或运算满足下面规律:
  • 0^a = a;
  • a^a = 0;
  • a^b^c = a^c^b;
巧妙运用异或可以高效解决很多问题,比如 找出数组中只出现了一次的数(除了一个数只出现一次外,其他数都是出现两次),以及它的升级版:数组中只出现1次的两个数字(百度面试题)
> 不用判断语句来实现求绝对值。
def bit_abs(num):
    negative = num >> 31
    return (num ^ negative) - negative
这里假设程序运行环境中操作系统为32位,int型整数(不考虑整数溢出)用32位存储,因此可以用 num>>31 取出符号位,后面的部分留给大伙证明。
Divide two integers without using multiplication, division and mod operator.
就是说不用乘法,除法,求模运算来实现两个整数相除,看起来很简单,我可以用除数减去被除数,直到除数小于被除数,记录减法操作的次数即可。假设是计算m/n,那么时间复杂度为O(m/n)。用Python实现后,Time Limit Exceeded。我们考虑有没有更加优化的算法呢?
我们对除数减去被除数的过程稍作改进。假设求m/n,我们不一次次的 m-n,而是找到n的一个倍数,使得m-x*n尽可能小,这样能减少循环减法的次数,进而提高效率。我们知道在按位操作中,n << k相当于 n * 2^k,因此可以用2^k 来找合适的x。
我们需要这样的一个数字k,它使得n 2^k < m < n 2^(k+1), 然后用m - n*2^k,得到新的m'。再找相应的k',做减法,如此循环即可
http://brokendreams.iteye.com/blog/2084088
要求不用加减符号(包括负号)来实现加减法。
第1位的值有4种,0+0=0、1+0=1、0+1=1、1+1=0,这正好符合“异或”的情况。 
        第2位的值来自于第一位的进位加上本身的值,进位的情况也有4种,0+0=0、1+0=0、0+1=0,1+1=1,这正好符合“与”的情况。 
        考虑一般性,a+b就等同于a^b + (a&b) << 1,而这又是一个加法,可递归求解,出口就是当进位为0的时候。
  1. public static int add(int a, int b){  
  2.         return b == 0 ? a : add(a ^ b ,(a & b) << 1);  
  3.     }  

那么减法怎么搞呢?减法也能用加法表示嘛,比如a-b就等于a+(-b),但不能出现负号,我们知道Java中整型数值编码方式为补码,所以一个数对应的负数就这个数“取反加1”,
  1. public static int sub(int a, int b){  
  2.         return add(a, add(~b, 1));  
  3.     }  
http://codesam.blogspot.com/2011/01/bit-manipulation-tips-and-tricks-part-1.html
1. Multiply a number by a power of two using bit left shift
a << b = a * 2^b
2. Divide a number by a power of two using bit right shift
a >> b = a / 2^b
3. Toggle a specified bit in a bit string without effecting other bits
bit_string = bit_string ^ (1 << positionOfBitToToggle)
4. Checking if a bit is on or off without affecting other bits
int isAvailable (int bitString, int targetNum)
{
  return bit_string & (1 << targetNum);
}
http://codesam.blogspot.com/2011/01/bit-manipulation-tips-tricks-part-2.html
1. Turning a bit off without affecting other bits
turnBitOff (int bitString, int bitPosition)
{
  return bitString & ~(1 << bitPosition);
}
2. Turning a bit on without affecting other bits
turnBitOn (int bitString, int bitPosition)
{
  return bitString || (1 << bitPosition);
}
http://www.1point3acres.com/bbs/thread-73742-1-1.html
再准备面试的时候总结了一下关于bit manipulation可能用到的东西。在这里和大家分享一下~
x ^ 0s = x      x & 0s = 0   x | 0s = x
x ^ 1s = ~x   x & 1s = x    x | 1s = 1s
x ^ x  = 0      x & x = x     x | x  = x

boolean getBit(int i, int num){
        return ( (num & (1 << i)) != 0 );
}

int setBit(int i, int num){
        return num | (1 << i);
}

int clearBit(int num, int i) {
        int mask = ~(1 << i);
        return num & mask;
}

int clearBitMSBthroughI(int num, int i){
        int mask = (1<< i) -1;
        return num & mask;
}

int clearBitsIThrough0(int i, int num) {
        int mask = ~( (1 << (i+1) )  -1 );
        return num & mask;
}

int updateBit(int i, int num, int v){
        int mask = ~(1 << i);
        return (num & mask) | (v << i);
}
http://blog.csdn.net/earthma/article/details/46762943
值为1且最靠右的位元置为0 (如果存在): 0101 1110 => 010 1100 : x&(x-1)
值为0且最靠右的位元置为1 (如果存在): 0101 1110 => 010 1111 : x|(x+1)
将尾部的所有连续的1置为0(如果存在): 0101 0111 => 0101 0000 : x&(x+1)
将尾部的所有连续的0置为1(如果存在): 0101 1000 => 0101 1111 : x|(x-1)
将最靠右的0置为1(如果存在),且其他位元置为0: 0101 0111 => 0000 1000 :  ~x&(x+1)
将最靠右的1置为0(如果存在),且其他位元置为1: 0101 1000 => 1111 0111 : ~x|(x-1)
将尾部的连续0置为1(如果存在),且其他位元置为0: 0101 1000 => 0000 0111 : ~x&(x-1) or ~(x|-x) or (x&-x)-1
将尾部的连续1置为0(如果存在),且其他位元置为1: 0101 0111 => 1111 1000 : ~x|(x+1)
保留最右的1(如果存在),其他位元置为1: 0101 1000 => 0000 1000 :x&(-x)
最靠右的1及其右边的位元置为1,左边置为0: 0101 1010 => 0000 1111 : x^(x-1)
最靠右的0及其右边的位元置为1,左边置为0: 0101 1010 => 0000 0111 : x^(x+1)
右侧首个连续的1置为0: 0101 1100 => 0100 0000 (((x|(x-1))+1&x)  or ((x&-x)+x)&x


进阶:
求比某个数大且位元1的个数相同的数 例如 xxx0 1111 0000 => xxx1 0000 0111
令 x = xxx0 1111 0000
s = x&-x
r = s+x
y = r | ( ( x ^ r ) << 2 / s)

两数的平均数:
(x&y) + ((x^y)>>1) 下取整
(x|y)   - ((x^y)>>1) 上取整

统计位元‘1’的个数:
1.二分搜索法:
x = (x & 0x5555 5555) + ((x>>1) & 0x5555 5555)
x = (x & 0x3333 3333) + ((x>>2) & 0x3333 3333)
x = (x & 0x0F0F 0F0F) + ((x>>4) & 0x0F0F 0F0F)
x = (x & 0x00FF 00FF) + ((x>>8) & 0x00FF 00FF)
x = (x & 0x0000 FFFF) + ((x>>16) & 0x0000 FFFF)
例举一个八位数:
x = 1 0 1 1 1 1 0 0  
x1 = 01 10 10 00
x2 = 0011 0010
x3 = 00000101 = 5
上述代码中有多余的与操作
可以写成如下简单代码:
int pop(unsigned x){
x = x - ((x>>1) & 0x5555 5555)
x = (x & 0x3333 3333) + ((x>>2) & 0x3333 3333)
x = (x+(x>>4)) & 0x0F0F 0F0F
x = x+(x>>8)
        x = x + (x>>16)
return x& 0x0000 003F
}
第一行中x的值是由以下公式而来:
pop(x) =  x - [x/2] - [x/4]-···-[x/2^31]


[LeetCode] Divide Two Integers (Java) | Life In Code


[LeetCode] Divide Two Integers (Java) | Life In Code
Divide two integers without using multiplication, division and mod operator.
  1. a本来是想一直-b,然后减到<0了,算counter。但是这样慢,所以类似c++ vector的思路,每次发现还没减没,那减数就翻倍(b <<= 1)
  2. 然后到了一定程度,b实在太大了,大于a剩余的部分了,那么就停止。然后剩下的a再一点点开始减,b回归成最开始的值,重做这两步。
重点是一旦超过,b应该不要一下回到原始值,而是应该一点一点/2这样做
We can keep subtract divisor from dividend until dividend is smaller than 0, than count the subtract numbers. But it will costs a very long time if the divisor is very small comparing to dividend.
Shift can be used to solve this problem. We shift the divisor left until it just smaller than dividend but if we keep shifting one more bit, it’s larger than dividend. Than we can add the shifted value to the result and subtract the shifted value from dividend. Keep doing this until dividend is smaller than divisor. In fact, every integer can be represented by a set of base 2 so that shifting can be used.
One thing needs to be mentioned is that we need to convert the integer to long type. Otherwise the Math.abs() value of Integer.MIN_VALUE will be quite strange.

any number can be converted to the format of the following:
num=a_0*2^0+a_1*2^1+a_2*2^2+...+a_n*2^n
    public int divide(int dividend, int divisor) {
        long p = Math.abs((long)dividend);
        long q = Math.abs((long)divisor);
        
        int ret = 0;
        while (p >= q) {
            int counter = 0;
            while (p >= (q << counter)) {
                counter++;
            }
            ret += 1 << (counter - 1);
            p -= q << (counter - 1);
        }
        
        if ((dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0))
            return ret;
        else
            return -ret;
    }
http://segmentfault.com/a/1190000003789802
我们设想87 / 4,本来应该的得到21余3,那么如果我们把87忽略余数后分解一下,87 = 4 * 21 = 4 * 16 + 4 * 4 + 4 * 1,也就是87 = 4 * (1 * 2^4 + 0 * 2^3 + 1 * 2^2 + 0 * 2^1 + 1 * 2^0),也就是把商分解为27 = 1 * 2^4 + 0 * 2^3 + 1 * 2^2 + 0 * 2^1 + 1 * 2^0,所以商的二进制是10101。我们可以不断的将4乘2的一次方,二次方,等等,直到找到最大那个次方,在这里是2的四次方。然后,我们就从四次方到零次方,按位看商的这一位该是0还是1。
    public int divide(int dividend, int divisor) {
        if(dividend == Integer.MIN_VALUE && (divisor == 1 || divisor == -1)){
            return divisor == 1 ? Integer.MIN_VALUE : Integer.MAX_VALUE;
        }
        return (int)divideLong(dividend, divisor);
    }
    
    public long divideLong(long dd, long dv){
        boolean isPos = (dd > 0 && dv > 0) || (dd < 0 && dv < 0); 
        dd = Math.abs(dd);
        dv = Math.abs(dv);
        int digits = 0;
        // 通过将除数乘2,乘4,乘8,一直乘下去,找到商的最高的次方
        // 比如87/4=21,商的最高次方是4,即2^4=16,即4 * 16 < 87
        while(dv <= dd){
            dv <<= 1;
            digits++;
        }
        // 重置除数,把最高次方减1得到实际最高位,刚才循环中多加了一次
        long res = 0;
        dv >>= digits;
        digits--;
        // 看商的每一位是否应该为1
        while(digits >= 0){
            if(dd >= (dv << digits)){
                dd -= dv << digits;
                res += 1 << digits;
            }
            digits--;
            System.out.println(res);
        }
        return isPos ? res : - res;
    }

https://gist.github.com/xuelangZF/32b1ccc98b8dd4ce67e9
就是说不用乘法,除法,求模运算来实现两个整数相除,看起来很简单,我可以用除数减去被除数,直到除数小于被除数,记录减法操作的次数即可。假设是计算m/n,那么时间复杂度为O(m/n)。用Python实现后,Time Limit Exceeded。我们考虑有没有更加优化的算法呢?
我们对除数减去被除数的过程稍作改进。假设求m/n,我们不一次次的 m-n,而是找到n的一个倍数,使得m-x*n尽可能小,这样能减少循环减法的次数,进而提高效率。我们知道在按位操作中,n << k相当于 n * 2^k,因此可以用2^k 来找合适的x。
我们需要这样的一个数字k,它使得n 2^k < m < n 2^(k+1), 然后用m - n*2^k,得到新的m'。再找相应的k',做减法,如此循环即可
http://blog.csdn.net/linhuanmars/article/details/20024907
对于这道题目,因为不能用乘除法和取余运算,我们只能使用位运算和加减法。比较直接的方法是用被除数一直减去除数,直到为0。这种方法的迭代次数是结果的大小,即比如结果为n,算法复杂度是O(n)。

那么有没有办法优化呢? 这个我们就得使用位运算。我们知道任何一个整数可以表示成以2的幂为底的一组基的线性组合,即num=a_0*2^0+a_1*2^1+a_2*2^2+...+a_n*2^n。基于以上这个公式以及左移一位相当于乘以2,我们先让除数左移直到大于被除数之前得到一个最大的基。然后接下来我们每次尝试减去这个基,如果可以则结果增加加2^k,然后基继续右移迭代,直到基为0为止。因为这个方法的迭代次数是按2的幂知道超过结果,所以时间复杂度为O(logn).

这种数值处理的题目在面试中还是比较常见的,类似的题目有Sqrt(x)Pow(x, n)等。上述方法在其他整数处理的题目中也可以用到,大家尽量熟悉实现这些问题
  1. public int divide(int dividend, int divisor) {  
  2.     if(divisor==0)  
  3.         return Integer.MAX_VALUE;  
  4.       
  5.     int res = 0;  
  6.     if(dividend==Integer.MIN_VALUE)  
  7.     {  
  8.         res = 1;  
  9.         dividend += Math.abs(divisor);  
  10.     }  
  11.     if(divisor==Integer.MIN_VALUE)  
  12.         return res;  
  13.     boolean isNeg = ((dividend^divisor)>>>31==1)?true:false;  
  14.     dividend = Math.abs(dividend);  
  15.     divisor = Math.abs(divisor);  
  16.     int digit = 0;  
  17.     while(divisor<=(dividend>>1))  
  18.     {  
  19.         divisor <<= 1;  
  20.         digit++;  
  21.     }  
  22.     while(digit>=0)  
  23.     {  
  24.         if(dividend>=divisor)  
  25.         {  
  26.             dividend -= divisor;  
  27.             res += 1<<digit;  
  28.         }  
  29.         divisor >>= 1;  
  30.         digit--;  
  31.     }  
  32.     return isNeg?-res:res;  
  33. }  
那么有没有办法优化呢? 这个我们就得使用位运算。我们知道任何一个整数可以表示成以2的幂为底的一组基的线性组合,即num=a_0*2^0+a_1*2^1+a_2*2^2+…+a_n*2^n。基于以上这个公式以及左移一位相当于乘以2,我们先让除数左移直到大于被除数之前得到一个最大的基。然后接下来我们每次尝试减去这个基,如果可以则结果增加加2^k,然后基继续右移迭代,直到基为0为止。因为这个方法的迭代次数是按2的幂知道超过结果,所以时间复杂度为O(logn)。
http://oj.leetcode.com/problems/divide-two-integers/
http://www.acmerblog.com/leetcode-divide-two-integers-5977.html
http://jane4532.blogspot.com/2013/06/divide-2-integersleetcode.html

Also check Bit Hack Misc
Read full article from [LeetCode] Divide Two Integers (Java) | Life In Code

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts