15个使用频率极高的基础算法题(附完整代码)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了15个使用频率极高的基础算法题(附完整代码)相关的知识,希望对你有一定的参考价值。
-
合并排序,将两个已经排序的数组合并成一个数组,当中一个数组能容下两个数组的全部元素
一般来说,合并两个已经有序的数组。首先是开一个能存的下两个数组的第三个数组,可是题目中已经说了。当中一个数组能所有存的下,显然就不应该浪费空间了。
从前往后扫的话,数据要存在大数组的前头,这样每次要把大数组的元素一次后移一位,显然不是什么好主意,所以我们从后往前存。
#include<iostream> #include<cstdlib> using namespace std; int cc[10]; int tt[5]; void init() { srand((unsigned)time(NULL)); int num = rand() % 5; for(int i = 0; i < 5; i++) { cc[i] = num; num += rand() % 10 + 1; } num = rand() % 5; for(int i = 0; i < 5; i++) { tt[i] = num; num += rand() % 10 + 1; } } void merge() { int i = 4, j = 4, idx = 9; while(i>=0 && j>=0) { if(cc[i] > tt[j]) cc[idx--] = cc[i--]; else cc[idx--] = tt[j--]; } while(i>=0) cc[idx--] = cc[i--]; while(j>=0) cc[idx--] = tt[j--]; } int main() { init(); for(int i = 0; i < 5; i++) printf("%d ", cc[i]); putchar(10); for(int i = 0; i < 5; i++) printf("%d ", tt[i]); putchar(10); merge(); for(int i = 0; i < 10; i++) printf("%d ", cc[i]); putchar(10); getchar(); return 0; }
-
合并两个已经排序的单链表
不能创建第三条链表,用上两种办法进行合并
#include <iostream> using namespace std; struct node{ int data; node *next; }; void CreateNode(node *head) // 创建带有头结点的有序单链表 { node *s = head; int val = rand() % 5 + 1; for (int i = 0; i < 5; i++) { val += rand() % 5 + 1; node *t = new node; t->data = val; t->next = NULL; s = s->next = t; } } void PrintNode(node *head) { node *s = head; while (s = s->next) printf("%d ", s->data); putchar(10); } node* Merge_1(node *head1, node *head2) // 顺序扫描 { node *i = head1->next; node *j = head2->next; node *cc = new node; node *s = cc; while(i && j) { if(i->data < j->data) { s = s->next = i; i = i->next; } else { s = s->next = j; j = j->next; } } if(i) s->next = i; else s->next = j; return cc; } node* Merge_2(node *head1, node *head2) // 递归法 { if(head1 == NULL) return head2; if(head2 == NULL) return head1; node *cc = NULL; if(head1->data < head2->data) { cc = head1; cc->next = Merge_2(head1->next, head2); } else { cc = head2; cc->next = Merge_2(head1, head2->next); } return cc; } int main() { srand((unsigned)time(NULL)); node *LinkList1 = new node, *LinkList2 = new node; CreateNode(LinkList1); CreateNode(LinkList2); PrintNode(LinkList1); PrintNode(LinkList2); // LinkList1 = Merge_1(LinkList1, LinkList2); LinkList1->next = Merge_2(LinkList1->next, LinkList2->next); PrintNode(LinkList1); // 合并后的链表存在1中 getchar(); return 0; }
-
倒序打印一个单链表
#include <iostream> using namespace std; struct node{ int data; node *next; }; void CreateNode(node *&head) // 创建不带头结点的有序单链表 { head = new node; head->data = rand() % 5 + 1; node *s = head, *t = NULL; for(int i = 0; i < 5; i++) { t = new node; t->data = s->data + rand() % 5 + 1; s = s->next = t; } s->next = NULL; } void PrintNode(node *head) { node *s = head; while (s != NULL) { printf("%d ", s->data); s = s->next; } putchar(10); } void PrintNode_Reverse(node *head) { if(head->next != NULL) PrintNode_Reverse(head->next); printf("%d ", head->data); } int main() { srand((unsigned)time(NULL)); node *LinkList; CreateNode(LinkList); PrintNode(LinkList); PrintNode_Reverse(LinkList); putchar(10); getchar(); return 0; }
-
给定一个单链表的头指针和一个指定节点的指针。在O(1)时间删除该节点
參见博客:怎样在O(1)的时间里删除单链表的结点
-
找到链表倒数第K个节点
设两个指针。一个先向前走K步。然后两个指针同步移动,等先走的指针走到了末尾,后走的指针就在倒数第K个位置了。
#include <iostream> using namespace std; struct node{ int data; node *next; }; void CreateNode(node *&head) // 创建不带头结点的有序单链表 { head = new node; head->data = rand() % 5 + 1; node *s = head, *t = NULL; for(int i = 0; i < 10; i++) { t = new node; t->data = s->data + rand() % 5 + 1; s = s->next = t; } s->next = NULL; } void PrintNode(node *head) { node *s = head; while (s != NULL) { printf("%d ", s->data); s = s->next; } putchar(10); } void find(node *head, int num) { node *s = head, *t = head; for(int i = 0; i < num; i++) t = t->next; while(t) { s = s->next; t = t->next; } printf("place: %dth value:%d\n", num, s->data); } int main() { srand((unsigned)time(NULL)); node *LinkList; CreateNode(LinkList); PrintNode(LinkList); find(LinkList, 5); find(LinkList, 3); putchar(10); getchar(); return 0; }
-
反转单链表
用递归与非递归两种方法,注意检查链表仅仅有一个结点的时候反转函数不会出错
#include <iostream> using namespace std; struct node{ int data; node *next; }; void CreateNode(node *&head) // 创建不带头结点的有序单链表 { head = new node; head->data = rand() % 5 + 1; node *s = head, *t = NULL; for(int i = 0; i < 10; i++) { t = new node; t->data = s->data + rand() % 5 + 1; s = s->next = t; } s->next = NULL; } void PrintNode(node *head) { node *s = head; while (s != NULL) { printf("%d ", s->data); s = s->next; } putchar(10); } node* Reverse_1(node *head) // 非递归 { node *s = head, *t = head->next; s->next = NULL; while(t != NULL) { node *r = t->next; t->next = s; s = t; t = r; } return s; } void Reverse_2(node *front, node *n, node *&head) // 递归 { front->next = NULL; if(n != NULL) head = n; if(n != NULL && n->next != NULL) Reverse_2(n, n->next, head); if(n != NULL) n->next = front; } int main() { srand((unsigned)time(NULL)); node *LinkList; CreateNode(LinkList); PrintNode(LinkList); LinkList = Reverse_1(LinkList); // Reverse_2(LinkList, LinkList->next, *&LinkList); PrintNode(LinkList); putchar(10); getchar(); return 0; }
-
通过两个栈实现一个队列
參见博客:用两个栈实现队列
-
二分查找
#include <iostream> using namespace std; void BinarySearch(int cc[], int num, int key)// 数组, 数组个数, 待查数字 { int i = 0, j = num; int cnt = 0, mid = 0; while(i < j) { cnt++; mid = (i + j) >> 1; if(cc[mid] == key) { printf("%d %s, index: %d\n", cnt, cnt==1?
"time":"times", mid); return; } else if(cc[mid] < key) i = mid; else j = mid; } } int main() { int cc[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; BinarySearch(cc, 10, 3); getchar(); return 0; }
-
高速排序
两种稍微有些不一样的快排(传入參数不同)
#include <iostream> using namespace std; int cc[10]; void init() { srand((unsigned)time(NULL)); for(int i = 0; i < 10; i++) { int idx = rand()%10; while(cc[idx]) idx = rand()%10; cc[idx] = i+1; } } void show() { for(int i = 0; i < 10; i++) printf("%d ", cc[i]); putchar(10); } void QuickSort_1(int cc[], int num) { int s = 0, t = num-1; int base = cc[0]; if(num <= 1) return; while(s < t) { while(t > s && cc[t] >= base) t--; cc[s] = cc[t]; while(s < t && cc[s] <= base) s++; cc[t] = cc[s]; } cc[s] = base; QuickSort(cc, s); QuickSort(cc+s+1, num-s-1); } void QuickSort_2(int cc[], int l, int r) { if(l >= r) return; int s = l, t = r; int base = cc[l]; while(s < t) { while(t > s && cc[t] >= base) t--; cc[s] = cc[t]; while(s < t && cc[s] <= base) s++; cc[t] = cc[s]; } cc[s] = base; QuickSort_2(cc, l, s-1); QuickSort_2(cc, s+1, r); } int main() { init(); show(); //QuickSort_1(cc, sizeof(cc)/sizeof(int)); QuickSort_2(cc, 0, sizeof(cc)/sizeof(int)-1); show(); getchar(); return 0; }
-
获得一个int型的数中二进制中的个数
没明确这个题目的意思,我们就理解成两个小题好了:
(1)求一个int型数字的二进制位数,如6->110->3位数
(2)求这个int型数字的二进制中‘1‘的个数#include <iostream> using namespace std; int main() { int num; while(~scanf("%d", &num)) { int bits = 0, cnt = 0; int val = num; while(val) { if(val & 1) cnt++; bits++; val>>=1; } printf("%d has %d bit and %d '1' in binary\n", num, bits, cnt); } return 0; }
-
输入一个数组,实现一个函数。让全部奇数都在偶数前面
#include <iostream> using namespace std; int cc[10]; void init() { srand((unsigned)time(NULL)); for(int i = 0; i < 10; i++) { int idx = rand()%10; while(cc[idx]) idx = rand()%10; cc[idx] = i+1; } } void show() { for(int i = 0; i < 10; i++) printf("%d ", cc[i]); putchar(10); } void Sort(int cc[], int size) { int s = 0, t = size-1; while(s < t) { while(s < t && (cc[s]&1)) s++; while(t > s && !(cc[t]&1)) t--; cc[s] ^= cc[t]; cc[t] ^= cc[s]; cc[s] ^= cc[t]; } } int main() { init(); show(); Sort(cc, sizeof(cc)/sizeof(int)); show(); getchar(); return 0; }
-
推断一个字符串是否是还有一个字符串的子串
经典问题,用KMP算法。#include <iostream> using namespace std; char t[1000]; char p[100]; int f[100]; int cnt = 0; void KMP() //须要使用的參数是char t[]长串, char p[]模式串. { int n = strlen(t); int m = strlen(p); /////计算模式串的失配边 f[0] = f[1] = 0; for(int i = 1; i < m; i ++) { int j = f[i]; while(j && p[i] != p[j])j = f[j]; f[i+1] = p[i] == p[j]?j+1:0; } int j = 0; for(int i = 0; i < n; i ++) { while(j && t[i] != p[j]) j = f[j]; if(p[j] == t[i])j ++; if(j == m) //匹配成功 cnt ++; } } int main() { cnt = 0; gets(t); gets(p); KMP(); if(cnt >= 1) printf("match!\n"); else printf("not match!\n"); getchar(); return 0; }
-
把一个int型数组中的数字拼成一个串,这个串代表的数字最小
关键就是要把int数组排个序,排序的cmp代码应该这样:假设两个数是A和B,那么应该比較AB和BA的大小,比如12、15。就要比較1215和1512的大小了。所以为了方便我们把int先转成char型,这样比較的时候直接strcat很方便。#include <iostream> using namespace std; void CreateArray(int *cc, int num) { srand((unsigned int)time(NULL)); for(int i = 0; i < num; i++) cc[i] = rand() % 50; } int cmp(const void *a, const void *b) { char *s1 = new char[10]; char *s2 = new char[10]; strcpy(s1, *(char**)a); strcat(s1, *(char**)b); strcpy(s2, *(char**)b); strcat(s2, *(char**)a); return strcmp(s1, s2); } void ConvertToMinString(int *cc, int len) { char** str = (char**)new int[len]; for(int i = 0; i < len; i++) { str[i] = new char[5]; sprintf(str[i], "%d", cc[i]); } qsort(str, len, sizeof(char*), cmp); for(int i = 0; i < len; i++) printf("%s ", str[i]); putchar(10); } int main() { int cc[5]; CreateArray(cc, 5); ConvertToMinString(cc, 5); getchar(); return 0; }
-
输入一颗二叉树。输出它的镜像(每一个节点的左右子节点交换位置)
用上递归和非递归两种方法。#include <iostream> #include <queue> using namespace std; struct node{ int val; node *left; node *right; }; void insert(node *&root, int data) { if(root == NULL) { root = new node; root->val = data; root->left = root->right = NULL; return; } if(root->val > data) insert(root->left, data); else insert(root->right, data); } node* build() { node *root = NULL; insert(root, 10); for(int i = 8; i <= 12; i++) { if(i == 10)continue; insert(root, i); } return root; } void showTree(node *root) { if(root == NULL) return; printf("%d ", root->val); showTree(root->left); showTree(root->right); } void Mirror_1(node *&root) // 递归方法 { if(root == NULL) return; node *t = root->left; root->left = root->right; root->right = t; Mirror_1(root->left); Mirror_1(root->right); } void Mirror_2(node *&root) // 非递归方法 { queue<node*> q; if(root != NULL) q.push(root); while(!q.empty()) { node *n = q.front(); q.pop(); node *t = n->left; n->left = n->right; n->right = t; if(n->left != NULL) q.push(n->left); if(n->right != NULL) q.push(n->right); } } int main() { node *root = build(); showTree(root);putchar(10); Mirror_1(root); showTree(root);putchar(10); Mirror_2(root); showTree(root);putchar(10); getchar(); return 0; }
-
输入两个链表,找到它们第一个公共节点
也就是说这两个链表的形状就像“Y”一样。
我想到了两种办法:
①两个链表先分别枚举一遍,计算出两个链表的长度,如果是N和M。如果长链是N的长度,即N>=M,让长链先走N-M步。短链指针先不走,这样两个指针到结尾的距离都同样了,然后两个指针一边同步走一边进行比較,什么时候两个指针同样,当前节点就是第一个公共节点了。时间复杂度:O(n+m)
②设一个map或者其它键值对(哈希表),然后第一个链表走一步。依据其地址或主键建立索引,第二个链表走一步。依据其地址或主键建立索引。两个链表在遍历的时候分别去检索索引。什么时候发现已经记录了,那么当前节点就是第一个公共节点了。如果两个链表在相交之前的长度各自是N和M,则空间复杂度是O(max(n, m)*2)。其时间复杂度是O(max(n, m) * 2)。
相比之下我觉得②要好的多,毕竟时间相比于空间重要太多了。所以以下我给出了②的代码,用地址作为索引。事实上我觉得怎样创建这样交叉的链表和怎样存储指针地址也能够作为一个题目哈。#include <iostream> #include <map> using namespace std; struct node{ int val; node *next; }; node* buildFirTree() // 第一个链表有20个节点 { node *root = new node; root->val = 1; node *s = root, *t = root; for(int i = 2; i <= 20; i++) { t = new node; t->val = i; s = s->next = t; } s->next = NULL; return root; } node* buildSecTree(node *firnode)// 第二个链表创建5个结点,然后接到第一个链表的第8个结点上 { node *root = new node; root->val = 11; node *s = root, *t = root; for(int i = 2; i <= 5; i++) { t = new node; t->val = 10 + i; s = s->next = t; } node *k = firnode; for(int i = 0; i < 7; i++) k = k->next; s->next = k; return root; } void disp(node *root) { node *t = root; while(t) { printf("%d ", t->val); t = t->next; } putchar(10); } node *GetFirstCommonNode(node *fir, node *sec) { map<long, bool> mp; mp.clear(); while(fir && sec) { if(mp[(long)fir] == true) return fir; mp[(long)fir] = true; fir = fir->next; if(mp[(long)sec] == true) return sec; mp[(long)sec] = true; sec = sec->next; } return NULL; } int main() { node *fir = buildFirTree(); printf("First linklist: ");disp(fir); node *sec = buildSecTree(fir); printf("second linklist: ");disp(sec); node *common = GetFirstCommonNode(fir, sec); if(common != NULL) printf("common node is: %d\n", common->val); else printf("There is no common node\n"); getchar(); return 0; }
以上是关于15个使用频率极高的基础算法题(附完整代码)的主要内容,如果未能解决你的问题,请参考以下文章
mser 最大稳定极值区域(文字区域定位)算法 附完整C代码
天池赛题解析:零基础入门语义分割-地表建筑物识别-CV语义分割实战(附部分代码)