天空一声巨响,迪宝闪亮登场。哈哈哈数据结构刷题又来了。实践是检验真理的唯一标准,最近感觉到自己的代码功底越来越深了,看来多写代码确实很有帮助。这次又带来最新的五道题目,来跟我一起去看看把。(顺便提一下,现在我在PTA上浙大《数据结构》这个题库已经排名1/3105了哦!!!)

电话聊天狂人

这道题我就是使用了哈希函数+分离链接法,然后第一次还超时了,后来将哈希函数改了后,降低了装填因子,就AC了。整体难度不大。
此题代码如下:

  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4. class Node{
  5. public:
  6. string s;
  7. long int value;
  8. Node* next;
  9. Node(){ next = NULL;value = 0; }
  10. long int Getvalue() { return this->value; }
  11. Node* Getnext() { return this->next; }
  12. void Setvalue(long int num) { value = num; }
  13. void Setnext(Node* a) { next = a; }
  14. };
  15. class Nodearray{
  16. public:
  17. Node* head;
  18. Node* tail;
  19. int total;
  20. Nodearray(){
  21. head = NULL;
  22. tail = NULL;
  23. total = 0;
  24. }
  25. void Addnum(string num){
  26. if (head == NULL){
  27. head = new Node;
  28. head->s = num;
  29. head->Setvalue(1);
  30. head->Setnext(NULL);
  31. tail = head;
  32. }
  33. else{
  34. Node* p = this->head;
  35. Node* tempp = p;
  36. while(p != NULL){
  37. if(num > p->s){
  38. tempp = p;
  39. p = p->Getnext();
  40. }
  41. else{
  42. Node* temp;
  43. temp = new Node;
  44. temp->s = num;
  45. temp->Setvalue(1);
  46. if(p == this->head){
  47. temp->Setnext(p);
  48. this->head = temp;
  49. return;
  50. }else{
  51. temp->Setnext(p);
  52. tempp->Setnext(temp);
  53. return;
  54. }
  55. }
  56. }
  57. tempp->Setnext(new Node);
  58. tempp = tempp->Getnext();
  59. tempp->s = num;
  60. tempp->Setvalue(1);
  61. tempp->Setnext(NULL);
  62. return;
  63. }
  64. }
  65. bool Findnum(string num){
  66. Node* p1 = head;
  67. Node* p2 = head;
  68. if (head == NULL){
  69. return false;
  70. }
  71. else{
  72. if (head->s == num){
  73. head->value ++;
  74. return true;
  75. }
  76. else
  77. p2 = p2->Getnext();
  78. while (p2 != NULL){
  79. if (p2->s == num){
  80. p2->value ++;
  81. return true;
  82. }
  83. p1 = p1->Getnext();
  84. p2 = p2->Getnext();
  85. }
  86. }
  87. return false;
  88. }
  89. };
  90. int N,index;
  91. string s,s2;
  92. Nodearray a[8020];
  93. Node* temp;
  94. long int maxlen,maxnum;
  95. int Hash(string ss);
  96. int main(){
  97. cin >> N;
  98. for(int i = 0;i < N;i++){
  99. cin >> s;
  100. index = Hash(s);
  101. if(a[index].Findnum(s) == false)
  102. a[index].Addnum(s);
  103. cin >> s;
  104. index = Hash(s);
  105. if(a[index].Findnum(s) == false)
  106. a[index].Addnum(s);
  107. }
  108. maxnum = -1;
  109. maxlen = 0;
  110. for(int i = 0;i < 8020;i++){
  111. if(a[i].head == NULL)
  112. continue;
  113. temp = a[i].head;
  114. while(temp != NULL){
  115. if(maxnum == -1){
  116. s2 = temp->s;
  117. maxlen = 1;
  118. maxnum = temp->Getvalue();
  119. }
  120. else if(temp->Getvalue() > maxnum){
  121. s2 = temp->s;
  122. maxlen = 1;
  123. maxnum = temp->Getvalue();
  124. }
  125. else if(temp->Getvalue() == maxnum){
  126. maxlen ++;
  127. if(temp->s < s2)
  128. s2 = temp->s;
  129. }
  130. temp = temp->Getnext();
  131. }
  132. }
  133. cout<<s2<<' '<<maxnum;
  134. if(maxlen != 1)
  135. cout<<' '<<maxlen;
  136. return 0;
  137. }
  138. int Hash(string ss){
  139. int num = 0;
  140. for(int i = 0;i < ss.size();i++)
  141. num += ((int)ss[i] - 48)*((int)ss[i] - 48)*((int)ss[i] - 48);
  142. return num;
  143. }

Hashing

代码如下:

  1. #include <iostream>
  2. #include <cmath>
  3. using namespace std;
  4. const int maxn = 100005;
  5. typedef long long ll;
  6. int TableSize;
  7. bool a[maxn];
  8. bool isPrime(int m) {
  9. if(m <= 1) return false;
  10. int k = (int)sqrt(m);
  11. for(int i = 2; i <= k; ++i) {
  12. if(m % i == 0) return false;
  13. }
  14. return true;
  15. }
  16. int NextPrime(int m) {
  17. if(m % 2 == 0 || m == 1)
  18. m++;
  19. while(!isPrime(m)) m += 2;
  20. return m;
  21. }
  22. int Hash(int x) {
  23. return x % TableSize;
  24. }
  25. void Insert(int x) {
  26. int p = Hash(x);
  27. if(!a[p]) { //该位置没有元素
  28. a[p] = true;
  29. cout << p;
  30. } else {
  31. int newp = p;
  32. int i;
  33. for(i = 1; i <= TableSize; ++i) {
  34. newp = (p+i*i) % TableSize;
  35. if(!a[newp]) {
  36. a[newp] = true;
  37. cout << newp;
  38. return;
  39. }
  40. }
  41. cout << '-';
  42. }
  43. }
  44. int main() {
  45. int M, N, x;
  46. cin >> M >> N;
  47. TableSize = NextPrime(M);
  48. for(int i = 0; i < N; ++i) {
  49. cin >> x;
  50. Insert(x);
  51. if(i == N-1) cout << endl;
  52. else cout << ' ';
  53. }
  54. return 0;
  55. }

QQ账号的登录

依旧是哈希函数+分离链接法解决冲突,40分钟AC。
代码如下:

  1. #include<iostream>
  2. #include<string>
  3. using namespace std;
  4. class Node{
  5. public:
  6. string s;
  7. long int value;
  8. Node* next;
  9. Node(){ next = NULL;value = 0; }
  10. long int Getvalue() { return this->value; }
  11. Node* Getnext() { return this->next; }
  12. void Setvalue(long int num) { value = num; }
  13. void Setnext(Node* a) { next = a; }
  14. };
  15. class Nodearray{
  16. public:
  17. Node* head;
  18. Node* tail;
  19. int total;
  20. Nodearray(){
  21. head = NULL;
  22. tail = NULL;
  23. total = 0;
  24. }
  25. void Addnum(long int num,string pa){
  26. if (head == NULL){
  27. head = new Node;
  28. head->Setvalue(num);
  29. head->s = pa;
  30. head->Setnext(NULL);
  31. tail = head;
  32. }
  33. else{
  34. Node* p = this->head;
  35. Node* tempp = p;
  36. while(p != NULL){
  37. if(num > p->Getvalue()){
  38. tempp = p;
  39. p = p->Getnext();
  40. }
  41. else{
  42. Node* temp;
  43. temp = new Node;
  44. temp->s = pa;
  45. temp->Setvalue(num);
  46. if(p == this->head){
  47. temp->Setnext(p);
  48. this->head = temp;
  49. return;
  50. }else{
  51. temp->Setnext(p);
  52. tempp->Setnext(temp);
  53. return;
  54. }
  55. }
  56. }
  57. tempp->Setnext(new Node);
  58. tempp = tempp->Getnext();
  59. tempp->s = pa;
  60. tempp->Setvalue(num);
  61. tempp->Setnext(NULL);
  62. return;
  63. }
  64. }
  65. bool Findnum(long int num){
  66. Node* p1 = head;
  67. Node* p2 = head;
  68. if (head == NULL){
  69. return false;
  70. }
  71. else{
  72. if (head->Getvalue() == num){
  73. return true;
  74. }
  75. else
  76. p2 = p2->Getnext();
  77. while (p2 != NULL){
  78. if (p2->Getvalue() == num){
  79. return true;
  80. }
  81. p1 = p1->Getnext();
  82. p2 = p2->Getnext();
  83. }
  84. }
  85. return false;
  86. }
  87. void Checknum(long int num,string pa){
  88. Node* p1 = head;
  89. Node* p2 = head;
  90. if (head == NULL)
  91. return;
  92. else{
  93. if (head->Getvalue() == num){
  94. if(head->s == pa)
  95. cout<<"Login: OK"<<endl;
  96. else
  97. cout<<"ERROR: Wrong PW"<<endl;
  98. return;
  99. }
  100. else
  101. p2 = p2->Getnext();
  102. while (p2 != NULL){
  103. if (p2->Getvalue() == num){
  104. if(p2->s == pa)
  105. cout<<"Login: OK"<<endl;
  106. else
  107. cout<<"ERROR: Wrong PW"<<endl;
  108. return;
  109. }
  110. p1 = p1->Getnext();
  111. p2 = p2->Getnext();
  112. }
  113. }
  114. return;
  115. }
  116. };
  117. int N,index;
  118. char c;
  119. long int t;
  120. string temp2,temp3;
  121. Nodearray a[8020];
  122. int Hash(string ss);
  123. int main(){
  124. cin >> N;
  125. for(int n = 0;n < N;n++){
  126. cin >> c >> t >> temp3;
  127. temp2 = to_string(t);
  128. index = Hash(temp2);
  129. if(c == 'N'){
  130. if(a[index].Findnum(t) == true)
  131. cout<<"ERROR: Exist"<<endl;
  132. else{
  133. a[index].Addnum(t,temp3);
  134. cout<<"New: OK"<<endl;
  135. }
  136. }
  137. else{
  138. if(a[index].Findnum(t) == false)
  139. cout<<"ERROR: Not Exist"<<endl;
  140. else
  141. a[index].Checknum(t,temp3);
  142. }
  143. }
  144. return 0;
  145. }
  146. int Hash(string ss){
  147. int num = 0;
  148. for(int i = 0;i < ss.size();i++)
  149. num += ((int)ss[i] - 48)*((int)ss[i] - 48)*((int)ss[i] - 48);
  150. return num;
  151. }

Hashing-Hard Version

这道题需要动点脑子,想清楚过程和规则后再下手。这里我先使用了希尔排序进行排序,再用查表的方式+某种判断算法来判断出下一个填入的数字是什么。
代码如下:

  1. #include<iostream>
  2. #include<cmath>
  3. using namespace std;
  4. int N,start,index;
  5. int total = 0;
  6. int *a,*b;
  7. int c[100000];
  8. void HSort1(int *H,int n);
  9. int main(){
  10. cin >> N;
  11. a = new int[N];
  12. b = new int[N];
  13. for(int i = 0;i < N;i++){
  14. cin >> a[i];
  15. b[i] = a[i];
  16. }
  17. HSort1(b,N);
  18. for(int i = 0;i < N;i++){
  19. if(b[i] != -1){
  20. start = i;
  21. break;
  22. }
  23. }
  24. int flag;
  25. while(total != N - start + 1){
  26. flag = 0;
  27. for(int i = start;i < N;i++){
  28. if(c[b[i]] == 1)
  29. continue;
  30. index = b[i] % N;
  31. if(a[index] == b[i]){
  32. c[b[i]] = 1;
  33. if(total == 0)
  34. cout<<b[i];
  35. else
  36. cout<<' '<<b[i];
  37. break;
  38. }
  39. for(int j = index;j < index + N;j++){
  40. if(c[a[j % N]] != 1 && a[j % N] != b[i])
  41. break;
  42. if(a[j % N] == b[i]){
  43. c[b[i]] = 1;
  44. if(total == 0)
  45. cout<<b[i];
  46. else
  47. cout<<' '<<b[i];
  48. flag = 1;
  49. break;
  50. }
  51. }
  52. if(flag == 1)
  53. break;
  54. }
  55. total++;
  56. }
  57. return 0;
  58. }
  59. void HSort1(int *H,int n){
  60. int count = 1;
  61. while((int)pow(2,count) - 1 < n)
  62. count++;
  63. count--;
  64. int D;
  65. for(int i = count;i > 0;i--){
  66. D = (int)pow(2,i) - 1;
  67. for(int j = 0;j < D;j++){
  68. for(int k = j;k < n;k += D){
  69. if(k == j)
  70. continue;
  71. int t1 = H[k];
  72. for(int p = j;p < k;p += D){
  73. if(t1 < H[p]){
  74. for(int s = k;s > p;s -= D)
  75. H[s] = H[s-D];
  76. H[p] = t1;
  77. break;
  78. }
  79. }
  80. }
  81. }
  82. }
  83. }

KMP串的模式匹配

代码如下:

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define div 1000000007
const int maxn = 1000005;
const int inf  = 0x3f3f3f;
int N,M;
int nxt[maxn];
void getnxt(string t) {
    int len = t.length();
    int i = 0, j = -1; 
    nxt[0] = -1;
    while (i < len) {
        if (j == -1 || t[i] == t[j]) {
            i++, j++;
            if (t[i] == t[j])
                nxt[i] = nxt[j]; // next数组优化
            else
                nxt[i] = j;
        } else
            j = nxt[j];
    }
}

int KMP(string s, string t) {//s为文本串,t为模式串(短的那个)
    getnxt(t);
    int len1 = s.length();
    int len2 = t.length();
    int i = 0, j = 0, ans = 0;
    while (i < len1) {
        if (j == -1 || s[i] == t[j]) {
            i++, j++;
            if (j >= len2) {
                return i-j;
            }
        } else
            j = nxt[j];
    }
    return -1;
}
int main(){
    ios::sync_with_stdio(false);
    string String, Pattern;
    cin >> String;
    cin >> N;
    for(int i = 0; i < N; ++i) {
        memset(nxt, 0, sizeof(nxt));
        cin >> Pattern;
        int k = KMP(String, Pattern);
        if(k == -1) cout << "Not Found" << endl;
        else cout << String.substr(k) << endl;
    }
    return 0;
}

总结

这次是散列查找和KMP的专场。散列查找的问题或者说散列查找、哈希表本身不是很难用代码实现的查找算法,但是哈希算法却是一个非常重要的查找方法,值得我们细细品味。
欢迎对ECE/CS/AI感兴趣的小伙伴关注我,如果你对我的内容有什么建议的话,或者你也对算法和数据结构感兴趣的话,可以单独找我讨论,也欢迎在评论区留下你的声音。