【編程珠璣】第二章 二分尋找的巧妙應用

來源:互聯網
上載者:User

一,三個問題

A題:給定一個最多包含40億個隨機排列的32位整數的循序檔,找出一個不在檔案中的32位整數。

           1、在檔案中至少存在這樣一個數?

           2、如果有足夠的記憶體,如何處理?

           3、如果記憶體不足,僅可以用檔案來進行處理,如何處理?

答案:

           1、32位整數,包括-2146473648~~2146473647,約42億個整數,而檔案中只有40億個,必然有整數少了。

           2、如果採用位元思想來存放,則32位整數最多需要佔用43億個位。約512MB的記憶體空間  (2`32/8=512MB)

                 可以採用前一章的位處理方法。然後判斷每個int是否等於-1。因為-1的二進位表示是全1的。如果不等於-1。那麼說明某一位沒有置位。需要進行處理。

          3、記憶體不足,可以採用如下思想:

                      按最高位分為兩段,沒有出現的那個數,肯定在比較小的段裡面。

                      如果比較少的段最高位為1,那麼缺少的那個數的最高位也為1.

                      如果比較少的段最高位為0,那麼少的那個數的最高位也是0.

                      依次按以上方法去處理每個位。

                 演算法複雜度為O(n)。每次處理的部分都是上一次的一半。累加之後是O(n).

                 思想與找第K小數的思想是一樣的。只不過在這裡是有一個自動分割的過程。而找第k小數的時候,是隨機找一個數。

                 為了驗證思想這裡寫了段C代碼。

int get_lost(int *a, int *b, int *c, int alen, int bit)  {      int re = 0, v = 0, biter = 0, *t, citer, i = 0;      if (!a || !b || alen ==(unsigned long)( (1<< bit))) return -1;  //哪個數與最多可能擁有個數相等的時候,直接返回了。        while (bit--)      {          v = (1 << bit);          for (biter = citer = i = 0; i < alen; ++i)          {              if (a[i] & (1 << bit)) b[biter++] = a[i];              else c[citer++] = a[i];          }          if (biter <= citer)          {              re += v;              t = a; a = b; b = t;              alen = biter;          }          else          {              t = a; a = c; c = t;              alen = citer;          }      }      return re;  }  

a, b, c,都是三個等長的數組,alen表示其長度。bit表示位元。比如32位。bit=32.

re表示最後缺少的那個數。


B題:字串迴圈移位比如abcdef 左移三位,則變成defabc

_rev(0, i)

_rev(i, len)

_rev(0, len)

static void _res(char *a, int n)  {      int i = 0, j = n - 1;      char t;      while (i < j)      {          t = a[i]; a[i] = a[j]; a[j] = t;          ++i; --j;      }  }  char *rever(char *a, int n, int len)  {      int i, j;      if (!a || !n) return a;      _res(a, n);      _res(a + n, len - n);      _res(a, len);      return a;  }  

C 題:給定一個單詞集合,找出可以相互轉換的集合。比如abc bca cba都可以相互轉換。(變位詞)

         演算法如下:單詞按照字母進行排序,單詞間進行排序,這樣相同標識的單詞聚集到一起

這裡用C++來寫了。 

void gen_label(vector<string> &dict, map<string, vector<string> >&rec)  {      for (int i = 0; i < dict.size(); ++i)      {          string line = dict[i];          sort(line.begin(), line.end());          rec[line].push_back(dict[i]);      }        for (map<string, vector<string> >::iterator iter = rec.begin();iter != rec.end(); ++iter)      {          copy((iter->second).begin(), (iter->second).end(), ostream_iterator<string>(cout , " "));          cout << endl;      }  }  

2.6習題

1 、如果沒有時間進行預先處理,那麼可以找到這個單詞的標識符,然後掃描這個字典,標識符相同的輸出。

       如果可以預先處理,那麼可以先預先處理,用gen_label函數進行預先處理則可。


2、[關鍵看清楚:循序檔--->已經排好序的;  4300 000 000 大於2`32]

    按照二分法,按照最大值/2 分成兩部分,取較大的部分則可。實際上如果要形成嚴格地每次下降一半,那麼需要如下處理:

           1)如果最多有max個整數,比如對於有4個bit位的整形數。最多有16個數。

           2)如果給了32個數,實際上只需要取前面17個數就可以了,後面的不要了。(這17個數中一定有重複的數,只需要找出一個重複的就可以)

           3)把這17個數按首位分為兩堆,按理說一邊是8,一邊是9。如果發現分的一邊比9還要多出幾個。多出來的也不用看了。接下來處理9個的情況。

           4)這樣線上性時間內一定可以找到一個重複的數

    通過這種策略,可以保證最終可以找到那個重複的數。


5、如果是自己寫函數那麼就是前面所寫的_rev函數。

    如果是要調用rever()函數。那麼方法如下。

  

int main(void)  {      int n, len;      char *c = NULL;      while (scanf("%s", a) != EOF)      {          len = strlen(a);           c = a;          ++len;          while (len--)          {              rever(c, len - 1, len);              ++c;          }          printf("%s\n", a);      }      return 0;  }  

6、把名字對應的按鍵形成一個唯一的標識符,可以先對名字進行預先處理。

    用hash,

    hash_map<int, hash_set<string> > rec;


8、把最小的K個數找到O(nlogk),然後看這個K個數的和是否小於t.

9、搜尋次數C > nlgn/ (n - lgn)


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.