算法导论 4-2 - newdye的专栏 - 博客频道 - CSDN.NET


算法导论 4-2 - newdye的专栏 - 博客频道 - CSDN.NET
找出所缺的整数
某数组A[1..n]含有所有从0到n的整数,但其中有一个整数不再数组中。通过利用一个辅助数组B[0..n]来记录A中出现的整数,很容易在O(n)时间内找出所缺的整数。但是在这个问题中,我们却不能由一个单一的操作来访问A中的一个完整整数,因为A中的元素是以二进制表示的。我们所能用的唯一操作就是"取A[i]的第j位",这个操作所花的时间为常数。
证明:如果仅用此操作,仍能在O(n)时间内找出所缺的整数。

2 分析与解答

显然要运用递归思想,如果n为基数,那么0~n有(n+1)/2个奇数和(n+1)/2个偶数;同理当n为偶数时,有n/2+1个偶数,和n/2个奇数。
所以,假设如果A[1..n]中偶数个数不足,那么就要在A[1..n]的偶数元素中查找所缺整数,那么每次查找的数量就减半;将偶数元素左移一位得到的数组同样具有上述特性。反复应用此方法,直到两种情况:
  1. 奇数个数为0说明缺的位为1;
  2. 只剩一位时,不存在的那位就是所缺的;
这样就能得到基本递归算法,可以得到递归式T(n)=T(n/2)+D(n)+C(n);
在来看D(n)显然分解需要扫描整个A[1..n],所以D(n)=O(n);
对于C(n),算法应该不需合并,推测其时间复杂度为常数,即C(n)=O(1);
所以,若算法满足上述条件,递归式为T(n)为T(n)=T(n/2)+O(n),根据主定理可得,此递归式解为T(n)=O(n)。
证明:可以找到满足上述条件的算法。
设取A[i]的第j位操作为value(A[i],j);
因为整数在A中以二进制形式存储,那么value(A[i], 0)就代表A中元素的奇偶性;
而value(A[i], 1)就代表A中元素左移一位的奇偶性,以此类推,直至奇数个数为0或只剩1位。
http://www.cnblogs.com/longdouhzt/archive/2011/07/15/2107742.html
基本方法就是用二分法:
1, 遍历整数0到n的第一位,分成两个数组:P1[1] 和P0[1],分别代表第一位是1,0的数,并记录第一位是1的个数CountN,代价为O(n)
2, 遍历数组A[1...n]的第一位, 分成两个组:Q1[1]和Q0[1],分别代表第一位是1,0的数,并记录1的个数CountA,代价为O(n)
3, 比较CountN和CountA的值,结果可能有两种情况CountN = CountA,或者CountN = CountA + 1, 前者表明所缺数的第一位为0, 后者为1,代价为O(1)
4, 通过3的结果,随后我们可以在P1[1]和Q1[1](CountN>CountA,即缺少第一位为1的数)  或者 P0[1]和Q0[1](CountN=CountA,即缺少第一位为0的数)中的第2位中重复步骤1,2中的操作,记录数组P1[2]、P0[2]和 CountN'及Q1[2]、Q0[2]和CountA'。代价为O(n/2)和O(n/2), 经过比较后可得到所缺数第二位是0还是1,决定接下来比较P1[2]和Q1[2]  或者 P0[2]和Q0[2],代价O(1)
5, 不断重复Ceiling(lg(n))次,最后即可找到所缺数总代价为2* (O(n) + O(n/2) + ... +O(n/pow(2, k))) + ... + O(1)) = 2* O(2n) = 4*O(n) = O(n)
当然这里忽略了一个问题,如果A中缺了一个,这应该是n-1个数,则多出来的那个数是什么呢,如果和其他数有重复,上面的方法就无效了,情况变得相当复杂。因此上面的只适用于多出的一个数为0,或者干脆就只有n-1个数。
比较弱的方法:1到n所有数字加起来的和 减去 A[1]到A[n]的和

比较犀利的方法:凑m,m=4k-1,并且是4k-1>=n的最大整数(比如n=7,则m=7;n=16,则m=19;n=21,m=23以此类推)
那么只需要A[1]^A[2]^……^A[n-1]^A[n]^{A[m-2]^A[m-1]^A[m]},即可

原因:从4的整数倍开始,连续4个数字异或,结果为(例如4^5^6^7的结果是0;204^205^206 = 207;8^10^11=9)
所以0^1^2^……^m的结果为0,却哪个数字,则A[1]^A[2]^……^A[n-1]^A[n]^{A[m-2]^A[m-1]^A[m]}的结果就是所缺的数字

def loss_digital(A, n, i):
    if n == 1:
        if (A[0] >> i-1) == 0:
            return 1
        else:
            return 0

    #division O(n)
    array_odds = [x for x in A if (x >> (i-1)) & 0b1 == 1]
    array_evens = [x for x in A if (x >> (i-1)) & 0b1 == 0]

    #conque
    odds_actual = len(array_odds)
    if odds_actual == 0:
        return 1
    else:
        if n%2 == 0:
            odds_full = n/2
        else:
            odds_full = (n+1)/2
        if odds_actual == odds_full:
            return 2*loss_digital(array_evens, n-odds_full, i+1)
        else:
            return 1 + 2*loss_digital(array_odds, odds_actual, i+1)

http://blog.csdn.net/bin314/article/details/8179676
其实,我们可以通过以某种取法,避免对每个数字的所有位都进行该操作来提高效率。
对于数组A[1...n],其数据范围为[0,n],取n的最高为1的位,记为maxBit位,则有(1<<maxBit) <= n < ( 1 << (maxBit+1) )。
然后遍历A中的元素,获得数组中maxBit位为1的个数,记为cnt,如果cnt == ( n - (1<<maxBit) + 1 ),则说明maxBit位中的元素都有,即缺失的数字该位为0,否则为1,从而将问题转化为一个规模更小的子问题。
其时间复杂度:T(N) = T(N/2) + O(N).
n^(log2(1)+1) = n , 故T(N) = O(N).
const int maxn = 1024 ;
int array[maxn] ;
bool vis[maxn] ;

//返回j个第i个位,从低到高[0,31],返回值为1或者0
int getIthOfJ(int i,int j)
{
 return ( j & ( 1 << i ) ) > 0 ? 1 : 0 ;
}

//唯一可以访问array的操作,取第array[i]的第k位
int pick(int i, int k)
{
 return getIthOfJ(k, array[i]);
}
//创建一个数组,array[1]到array[n]包含有[0,n]中除了一个数字的所有其他数字
void buildArray(int n)
{
 if( n >= maxn - 1 ) 
 {
  n = maxn - 2 ;
 }
 
 srand(time(NULL));
 int i ;
 
 for( i = 1 ; i <= n + 1 ; i++) 
 {
  array[i] = i - 1 ;
 }

 int missingNumber = rand() % ( n + 1 ) ;
 printf("构造了一个数据范围为0到%d的数组,缺失的数字为%d\n",n,missingNumber);
 
 //移除一个随机数
 for( i = missingNumber + 1 ; i <= n ; i++) 
 {
  array[i] = array[i+1] ;
 }

 printf("构造如下数组:\n");
 for ( i = 1 ; i <= n ; i++)
 {
  printf("%d ",array[i]);
 }
 puts("");
}

//返回缺失的数字
int getTheMissingNumber(int n)
{
 //边界
 if ( n == 0 )
 {
  return 0 ;
 }

 int i , j , maxBit , cnt ;
 int ans = 0 ;
 for( maxBit = 31 ; maxBit >= 0 ; maxBit--) 
 {
  if( getIthOfJ(maxBit, n) == 1 )
  {
   break ;
  }
 }

 memset(vis,0,sizeof(bool)*(n+1));
 for ( i = 1 , cnt = 0 ; i <= n ; i++)
 {
  vis[array[i]] = 1 ;
  if ( getIthOfJ(maxBit, array[i]) == 1 )
  {
   //cnt记录array[i]中最高位maxbit为1的个数
   cnt++;
  }
 }

 if ( cnt == (n-(1<<maxBit)+1) )
 {
  //结果的最高位为0,拷贝最高位为0的数组进array
  for ( i = j = 0 ; i < (1<<maxBit) ; i++) if( vis[i] == 1 )
  {
   array[++j] = i ;
  }
  ans = getTheMissingNumber(j);
 }
 else
 {
  //结果的最高位为1,拷贝最高位为0的数组进array
  for ( i = ( 1 << maxBit ) , j = 0 ; i <= n ; i++) if( vis[i] == 1 )
  {
   array[++j] = i ^ ( 1 << maxBit ) ;
  }
  ans = (1 << maxBit) | getTheMissingNumber(j) ;
 }
 return ans ;
}

int main()
{
 int n ;
 while (~scanf("%d",&n))
 {
  buildArray(n);
  printf("所缺失的数字为:%d\n",getTheMissingNumber(n));
 }
}
Related: http://blog.csdn.net/jcwKyl/article/details/3957941
题目:数组A中包含n-1[0,n-1]内的不同整数,n个数中只有一个数不在所给的数组中。设计一个找到这个数的O(n)时间的算法。除了数组A自身以外,只能利用O(1)的额外空间。
解法二:异或运算。异或是个非常神奇的运算。设所缺的整数为k[0,n-1]区间中所有n个数的异或结果为s(n),异或运算满足交换率和结合率,所以s(n)可以被看作[0,n-1]中去掉k外的另外n-1个数的异或结果s(n-1)k的异或。也即:s(n)=s(n-1)^k,我们给等式两边同时异或s(n-1),等式变成了:s(n-1)^s(n)=s(n-1)^s(n-1)^k=k。而且,很明显s(n-1)其实就是数组A中所有元素的异或。所以,解法二就是:求出[0,n-1]内所有整数的异或结果s,再求出数组A中所有元素的异或结果t,所缺的整数就是s异或t
解法三:因为A自身也有n-1个位置。可以把A作为一个散列表,这样做虽然能够得到结果,但是破坏了数组A
至于《算法导论》思考题4-2的解法,在《算法艺术与信息学竞赛》上有解答。思路简述:自然数顺序的二进制表示最低位总是01交替出现,所以,首先读取数组A中所有元素的最低二进制位,如果得到的01的个数一样多,则说明所缺整数的最低二进制位为0,否则,哪个少,所缺整数的最低二进制位就是哪个。比如,我们得到所缺整数的最低二进制位为0,那么,说明数组A中最低二进制位为1的那些整数已经与此题无干,只需要在那些最低位为0的整数中找所缺整数。所以,时间复杂度是:T(n)=T(n/2)+n,计算:
n的上取整或下取整不影响时间复杂度。即T(n)=O(n)

Read full article from 算法导论 4-2 - newdye的专栏 - 博客频道 - CSDN.NET

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