1.
寫一個程序, 要求功能:求出用1,2,5這三個數不同個數組合的和為100的組合個數。
如:100個1是一個組合,5個1加19個5是一個組合。。。。 請用C++語言寫。
解決方案:
普通方法大家都會:

int main(){ int cnt = 0; for(int i = 0; i <= 100; i ++){ for(int j = 0; j <= 50; j ++){ for(int k = 0; k <= 20; k ++){ if(i + 2 * j + 5 * k == 100) cnt ++; } } } printf("%d\n", cnt); return 0; }
但是這循環是101*51*21次,復雜度大
由題知:假設X為1的個數,Y為2的個數,Z為5的個數,那么滿足X+2*Y+5*Z = 100
所以X+5*Z = 100 - 2*Y,很明顯X+5*Z是一個偶數,並且Z是<=20的,那么對Z做循環
Z=0, X=100,98,...,0
Z=1,X=95,93,...,1
Z=2,X=90,88,...0
.
.
.
Z=19,X=5,3,1
Z=20,X=0
所以結果只要求出100以內的偶數,95以內的奇數...最后是5以內的奇數再加一次就行了
對於一個奇數N求0到N之間的奇數個數為N/2+1,同樣的偶數個數為N/2+1
代碼如下:

int main(){ int sum = 0; for(int i = 0; i <= 100; i += 5){ sum += (100 - i) / 2 + 1; } printf("%d\n", sum); return 0; }
2.
寫一個鏈表,刪除一個結構體中指定的結點
解決方案:

#include <cstdio> #include <cstring> #include <cstdlib> struct stu{ int age; stu *next; }*list; struct stu *creatlist(int n){ stu *h, *p, *s; h = new stu; h->next = NULL; p = h; for(int i = 0; i < n; i ++){ s = new stu; p->next = s; scanf("%d", &s->age); s->next = NULL; p = s; } return h; } void output(stu *s){ s = s->next; while(s != NULL){ printf("%d ", s->age); s = s->next; } puts(""); } void deletelist(stu *h, int age){ stu *p = h; stu *s = h->next; while(s != NULL){ if(s->age == age){ p->next = s->next; s = s->next; } else{ p = p->next; s = s->next; } } } int main(){ int n; scanf("%d", &n); stu *s = creatlist(n); //output(s->next); int age; scanf("%d", &age); deletelist(s, age); output(s); return 0; }
3.
將二叉樹的兩個孩子換位置,即左變右,右變左。不能用遞規
解決方案:
1)根結點入隊列
2)取隊首元素並出列,並將該元素左右兒子進行交換
3)如果隊列不為空則跳到步驟2

#include <cstdio> #include <cstring> #include <cstdlib> #include <queue> using namespace std; struct tree{ tree *right; tree *left; }*list; void solve(tree *list){ queue <tree*> Q; Q.push(list); while(!Q.empty()){ tree *tmp = Q.front(); Q.pop(); swap(tmp->right, tmp->left); if(tmp->right != NULL) Q.push(tmp->right); if(tmp->left != NULL) Q.push(tmp->left); } }
4.
38頭牛中選出3頭跑得最快的,使用一個每次只能供6頭比賽的場地,要求用最快的方法
解決方案:
38只取6只一組,6*6,取前3名,得3*6+2=20,用了6次
20只取5只一組,取前3名,得到3*4=12,用了4次
12只分兩組取前3名,得3*2=6,用了2次
最后再加1次
累計13次
5.
n從1開始,每個操作可以選擇對n加1或者對n加倍。若想獲得整數2013,最少需要多少個操作
解決方案:
直接進行計算,奇數減1除2,偶數直接除以2,2013>1006>503>251>125>62>31>15>7>3>1
再反過來計算從1到2013的次數,為18次
6.
如下函數,在32bit系統foo(2^31-3)的值是:
Int foo(int x)
{
Return x&-x;
}
解決方案:
這題是先計算31-3再計算2異或28的,然后進行 x & -x
對於x & -x的含義:返回值為0,表示x=0;返回值為1,表示x為奇數;返回值為其他數,表示x為x與2^64的最大公約數,即二進制中從右到左的第一個1出現的位數
擴展:x & (x-1) 表示x進進制中1的個數,每執行一次x = x&(x-1),會將x用二進制表示時最右邊的一個1變為0,因為x-1將會將該位(x用二進制表示時最右邊的一個1)變為0
所以可通過這個求得一個數是不是2的n次方,代碼如下

int func(int x) { if( (x&(x-1)) == 0 ) return 1; else return 0; } int main() { int x = 8; printf("%d\n", func(x)); }
7.
給兩個單向鏈表,求是否有公共節點並求該公共節點,要求使用空間最小算法
解決方案:
將鏈表A遍歷以及鏈表B遍歷,分別保存最后一個節點以及他們長度,若相同再證明有公共節點
如果他們長度相等,依次遍歷就行,如果長度不等,將長度長的先遍歷|len_a - len_b|(表示絕對值)
如圖
9.
static靜態在申請的時候不分配內存

struct A{ A() {} ~A() {} int m1; int m2; }; struct B{ B() {} ~B() {} int m1; char m2; static char m3; }; struct C{ C() {} virtual~C() {} int m1; short m2; }; int main(){ printf("%d %d %d\n", sizeof A, sizeof B, sizeof C); return 0; }
輸出的是:8 8 12
10.
定義棧的數據結構,要求添加一個min函數,能夠得到棧的最小元素。要求函數min、push以及pop的時間復雜度都是O(1)
解決方案:這題難點在於pop一個元素之后,怎樣確定棧中的最小元素,然后查找就要遍歷顯示不行,
那么就設定一個輔助棧,將每次數據棧中最小的元素依次入棧,見代碼(考慮整型)

#include <cstdio> #include <cstring> #include <stack> using namespace std; class Stack { public: void push(int num){ data_stack.push(num); if(!min_stack.size()) min_stack.push(num); else if(num <= min_stack.top()) min_stack.push(num); } void pop(){ if(data_stack.top() == min_stack.top()) min_stack.pop(); data_stack.pop(); } void output(){ printf("%d\n", min_stack.top()); } protected: private: stack <int > data_stack; stack <int > min_stack; }; int main(){ Stack s; s.push(3); s.output(); s.push(4); s.output(); s.push(2); s.output(); s.push(1); s.output(); s.pop(); s.output(); s.pop(); s.output(); s.push(0); s.output(); return 0; }
11.
求最大子和段
解決方案:從第一個數開始加,如果碰到和為負數則置0,否則和max值比較取最大值

#include <cstdio> #include <cstring> #include <stack> using namespace std; int a[8] = {1, -2, 3, 10, -4, 7, 2, -5}; int main(){ int sum = a[0], max = a[0]; for(int i = 1; i < 8; i ++){ if(sum + a[i] < 0) sum = 0; else sum += a[i]; if(max < sum) max = sum; } printf("%d\n", max); return 0; }
12.
查找最小的k個元素
解決方案:
朴素方案或者遍歷選擇最小K個或者快速排序選擇前K個,復雜度略高
可以先插入K個到數組中,然后每插入一個數和前K個比較,比最大的小才插入並刪除最大的
如何做到在K個當中查找最大的,可以用一個最大堆,或者用第10題兩個棧的做法(個人認為可以,只是彈棧的要換一種方式了)

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> using namespace std; multiset <int > m; int main(){ m.clear(); m.insert(3); m.insert(5); m.insert(4); m.insert(1); m.insert(7); m.insert(8); m.insert(2); m.insert(6); for(multiset<int > :: iterator it= m.begin(); it != m.end(); it ++){ cout<<*it<<endl; } return 0; }
參考別人的

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> using namespace std; const int k = 5; const int maxn = 1000; int max_heap[k + 1]; int ed, maxpos; void insert_min_heap(int data){ int child = 0; if(ed == k + 1){ if(data >= max_heap[1]) return; max_heap[1] = data; for(int i = 1; i * 2 <= k; i = child){ child = 2 * i; if((i * 2 + 1 <= k && max_heap[i*2] < max_heap[i*2+1])){ child ++; } if(max_heap[i] < max_heap[child]) swap(max_heap[i], max_heap[child]); else break; } return; } max_heap[ed ++] = data; for(int i = ed - 1; i > 1; i /= 2){ if(max_heap[i] > max_heap[i/2]) swap(max_heap[i], max_heap[i/2]); else break; } } int main(){ int n, data; ed = 1; while(~scanf("%d", &data)){ insert_min_heap(data); } for(int i = 1; i <= k; i ++) printf("%d ", max_heap[i]); puts(""); return 0; }
13.
寫一個堆排序

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> using namespace std; int n, a[100]; void init_heap(){ for(int i = n; i; i --){ int cur = i; while(true){ int next = -1; if((cur * 2 <= n) && (next < 0 || a[cur*2] > a[next])) next = cur * 2; if((cur * 2 + 1 <= n) && (a[cur*2+1] > a[next])) next = cur * 2 + 1; if(next < 0 || a[next] <= a[cur]) break; else{ swap(a[cur], a[next]); cur = next; } } } } void heap_sort(){ for(int i = n; i > 1; i --){ swap(a[1], a[i]); int cur = 1; while(true){ int next = -1; if((cur * 2 < i) && (next < 0 || a[cur*2] > a[next])) next = cur * 2; if((cur * 2 + 1 < i) && (a[cur*2+1] > a[next])) next = cur * 2 + 1; if(next < 0 || a[next] <= a[cur]) break; else{ swap(a[cur], a[next]); cur = next; } } } } int main(){ scanf("%d\n", &n); for(int i = 1; i <= n; i ++) scanf("%d", a + i); init_heap(); heap_sort(); for(int i = 1; i <= n; i ++){ printf("%d%c", a[i], i < n ? ' ' : '\n'); } }
14.
前序中序后序遍歷,創建二叉樹時采用隊列實現層序遍歷創建

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; struct Node{ int num; Node *l, *r; }; queue <Node * > Q; void creat_tree(Node *p, int num, int &f){ Node *s = new Node; s->num = num; s->l = s->r = NULL; if(f == 1){ p->l = s; f = 2; Q.push(s); return; } p->r = s; f = 1; Q.push(s); Q.pop(); } void dlr_output(Node *p){ if(p == NULL) return; printf("%d ", p->num); dlr_output(p->l); dlr_output(p->r); } void ldr_output(Node *p){ if(p == NULL) return; ldr_output(p->l); printf("%d ", p->num); ldr_output(p->r); } void lrd_output(Node *p){ if(p == NULL) return; lrd_output(p->l); lrd_output(p->r); printf("%d ", p->num); } int main(){ Node *root = new Node; Node *p = new Node; int f = 0; int num; while(!Q.empty()) Q.pop();//清空隊列 while(~scanf("%d", &num)){ if(f == 0){ root->num = num; root->l = NULL; root->r = NULL; f = 1; p = root; Q.push(p); continue; } p = Q.front(); creat_tree(p, num, f); } dlr_output(root);puts(""); ldr_output(root);puts(""); lrd_output(root);puts(""); return 0; }

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <string> #include <queue> using namespace std; struct TreeNode{ int value; TreeNode *left; TreeNode *right; }; TreeNode *creatTreeNode(int m){ TreeNode *node = new TreeNode; node->value = m; node->right = node->left = NULL; return node; } void DestroyTree(TreeNode *root){ if(root != NULL){ TreeNode *l = root->left; TreeNode *r = root->right; delete root; root = NULL; DestroyTree(l); DestroyTree(r); } } void connectTree(TreeNode *root, TreeNode *l, TreeNode *r){ if(root != NULL){ root->left = l; root->right = r; } } void solve(TreeNode *root); int main(){ TreeNode *node1 = creatTreeNode(1); TreeNode *node2 = creatTreeNode(2); TreeNode *node3 = creatTreeNode(3); TreeNode *node4 = creatTreeNode(4); TreeNode *node5 = creatTreeNode(5); TreeNode *node6 = creatTreeNode(6); TreeNode *node7 = creatTreeNode(7); connectTree(node1, node2, node3); connectTree(node2, node4, node5); connectTree(node3, node6, node7); solve(node1); //DestroyTree(node1); return 0; } void dlr(TreeNode *root){ if(!root) return; stack <TreeNode* > sta; TreeNode *tmp = root; while(tmp != NULL || !sta.empty()){ while(tmp != NULL){ printf("%d ", tmp->value); sta.push(tmp); tmp = tmp->left; } if(!sta.empty()){ tmp = sta.top(); sta.pop(); tmp = tmp->right; } } puts(""); } void ldr(TreeNode *root){ if(!root) return; stack <TreeNode* > sta; TreeNode *tmp = root; while(tmp != NULL || !sta.empty()){ while(tmp != NULL){ sta.push(tmp); tmp = tmp->left; } if(!sta.empty()){ tmp = sta.top(); sta.pop(); printf("%d ", tmp->value); tmp = tmp->right; } } puts(""); } void lrd(TreeNode *root){ if(!root) return; stack <TreeNode* > sta; TreeNode *cur, *pre = NULL; sta.push(root); while(!sta.empty()){ cur = sta.top(); if( (cur->left == NULL && cur->right ==NULL) || (pre != NULL && (pre == cur->left || pre == cur->right))){ printf("%d ", cur->value); sta.pop(); pre = cur; }else{ if(cur->right != NULL) sta.push(cur->right); if(cur->left != NULL) sta.push(cur->left); } } puts(""); } void solve(TreeNode *root){ dlr(root); ldr(root); lrd(root); }
15.
查找鏈表中倒數第k個結點
解決方案:
設置兩個指針,開始指向頭結點,然后第一個移動並計數,當移動了k-1次另一指針開始移動,復雜度為o(n)

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; struct Node{ int num; Node *next; }; Node *insert(Node *p, int num){ Node *s = new Node; s->num = num; s->next = NULL; p->next = s; return s; } int main(){ int num; Node *root = new Node; Node *p = root; int k; scanf("%d", &k); while(~scanf("%d", &num)){ p = insert(p, num); } int cnt = 0; Node *s1 = root; Node *s2 = root; while(s1 != NULL){ cnt ++; if(cnt >= k + 1){ s2 = s2->next; } s1 = s1->next; } printf("%d\n", s2->num); return 0; }
16.
在排序數組中查找和為給定值的兩個數字
解決方案:
確定第一個和最后一個的和,假如相加大於給定的數,則較大數前移,小於則較小數后移,相等就輸出

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; int a[100]; int main(){ int n; while(~scanf("%d", &n)){ for(int i = 0; i < n; i ++) scanf("%d", a + i); int num; scanf("%d", &num); int st = 0, ed = n - 1; while(true){ if(a[st] + a[ed] == num){ printf("%d %d\n", a[st], a[ed]); break; }else if(a[st] + a[ed] > num) ed --; else st ++; } } return 0; }
17.
O(logn)求Fibonacci數列
解決方案:
(轉)
下面介紹一種時間復雜度是O(logn)的方法。在介紹這種方法之前,先介紹一個數學公式:
{f(n), f(n-1), f(n-1), f(n-2)} ={1, 1, 1,0}n-1
(注:{f(n+1), f(n), f(n), f(n-1)}表示一個矩陣。在矩陣中第一行第一列是f(n+1),第一行第二列是f(n),第二行第一列是f(n),第二行第二列是f(n-1)。)
有了這個公式,要求得f(n),我們只需要求得矩陣{1, 1, 1,0}的n-1次方,因為矩陣{1, 1, 1,0}的n-1次方的結果的第一行第一列就是f(n)。這個數學公式用數學歸納法不難證明。感興趣的朋友不妨自己證明一下。
現在的問題轉換為求矩陣{1, 1, 1, 0}的乘方。如果簡單第從0開始循環,n次方將需要n次運算,並不比前面的方法要快。但我們可以考慮乘方的如下性質:
/ an/2*an/2 n為偶數時
an=
\ a(n-1)/2*a(n-1)/2 n為奇數時
要求得n次方,我們先求得n/2次方,再把n/2的結果平方一下。如果把求n次方的問題看成一個大問題,把求n/2看成一個較小的問題。這種把大問題分解成一個或多個小問題的思路我們稱之為分治法。這樣求n次方就只需要logn次運算了。
實現這種方式時,首先需要定義一個2×2的矩陣,並且定義好矩陣的乘法以及乘方運算。當這些運算定義好了之后,剩下的事情就變得非常簡單。完整的實現代碼如下所示。

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; struct matrix2by2{ matrix2by2( long long m00 = 0, long long m01 = 0, long long m10 = 0, long long m11 = 0 ) :m_00(m00), m_01(m01), m_10(m10), m_11(m11){} long long m_00; long long m_01; long long m_10; long long m_11; }; matrix2by2 matrixmultiply(const matrix2by2 &a, const matrix2by2 &b){ return matrix2by2( a.m_00 * b.m_00 + a.m_01 * b.m_10, a.m_00 * b.m_01 + a.m_01 * b.m_11, a.m_10 * b.m_00 + a.m_11 * b.m_10, a.m_10 * b.m_01 + a.m_11 * b.m_11 ); } matrix2by2 matrixpower(int n){ matrix2by2 matrix; if(n == 1) matrix = matrix2by2(1, 1, 1, 0); else if(n % 2 == 0){ matrix = matrixpower(n/2); matrix = matrixmultiply(matrix, matrix); } else if(n % 2 == 1){ matrix = matrixpower((n-1)/2); matrix = matrixmultiply(matrix, matrix); matrix = matrixmultiply(matrix, matrix2by2(1, 1, 1, 0)); } return matrix; } int main(){ printf("%d\n", matrixpower(10-1).m_00); return 0; }
18.
定義字符串的左旋轉操作:把字符串前面的若干個字符移動到字符串的尾部。如把字符串abcdef左旋轉2位得到字符串cdefab。請實現字符串左旋轉的函數。要求時間對長度為n的字符串操作的復雜度為O(n),輔助內存為O(1)。
解決方案:
假設這字符串簡化為XY,剛分三次操作即可,X旋轉,Y旋轉,XY旋轉

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; char s[] = "12345"; int n = 5; int k = 2; void reversestring(char *st, char *ed){ while(st < ed){ char tmp = *st; *st = *ed; *ed = tmp; st ++; ed --; } } int main(){ char *pst1 = s; char *ped1 = s + k - 1; char *pst2 = s + k; char *ped2 = s + n - 1; reversestring(pst1, ped1); reversestring(pst2, ped2); reversestring(pst1, ped2); printf("%s\n", s); return 0; }
19.
解決方案:從右上角開始查找,如果大就消除該列,如果小就消除該行
(修改)

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; bool find(int *a, int rows, int cols, int num){ int row = 0; int col = cols - 1; // printf("%d %d %d\n", a[0], num, a[rows * cols - 1]); for(int i = 0; i < rows; i ++){ for(int j = 0; j < cols; j ++){ // printf("%d ", a[i * cols + j]); } // puts(""); } if(a[0] > num || a[rows * cols - 1] < num) return false; //puts("asdf"); while(row < rows && col >= 0){ if(a[row * cols + col] == num) return true; if(a[row * cols + col] > num) col --; else row ++; } return false; } void test(){ int a[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}}; bool ans = find((int*)a, 4, 4, 15); if( ans ) puts("yes"); else puts("no"); } int main(){ test(); return 0; }
20.
旋轉數組二分查找

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; int a[111]; void solve(int st, int ed, int num){ int index1 = st, index2 = ed, mid = st; while(index1 <= index2){ int mid = index1 + index2 >> 1; if(a[mid] == num){ puts("yes"); return; } if(a[mid] >= a[st]){ if(num < a[mid] && num >= a[index1]) index2 = mid - 1; else index1 = mid + 1; }else{ if(num > a[mid] && num <= a[index2]) index1 = mid + 1; else index2 = mid - 1; } } puts("no"); } int main(){ int n; scanf("%d", &n); for(int i = 0; i < n; i ++) scanf("%d", a + i); int num; scanf("%d", &num); solve(0, n - 1, num); return 0; }
21.
給一個數,打印從1到這個數位數的最大數字

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; void PrintNum(char *num){ int len = strlen(num); bool f = 1; for(int i = 0; i < len; i ++){ if(f && num[i] == '0') continue; else f = 0; putchar(num[i]); } printf("\t"); } bool Increment(char *num){ bool isOverflow = false; int nTakeover = 0; int len = strlen(num); for(int i = len - 1; i >= 0; i --){ int sum = num[i] - '0' + nTakeover; if(i == len - 1) sum ++; if(sum >= 10){ if(i == 0) isOverflow = true; else{ sum -= 10; nTakeover = 1; num[i] = '0' + sum; } }else{ num[i] = '0' + sum; break; } } return isOverflow; } int main(){ int n; scanf("%d", &n); char *num = new char [n + 1]; memset(num, '0', n); num[n] = '\0'; while(!Increment(num)){ PrintNum(num); } delete [] num; return 0; }

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; void PrintNum(char *num){ int len = strlen(num); bool f = 1; for(int i = 0; i < len; i ++){ if(f && num[i] == '0') continue; else f = 0; putchar(num[i]); } printf("\t"); } void f(char *num, int len, int index){ if(index == len - 1){ PrintNum(num); return; } for(int i = 0; i < 10; i ++){ num[index + 1] = i + 48; f(num, len, index+1); } } int main(){ int n; scanf("%d", &n); char *num = new char [n + 1]; memset(num, '0', n); num[n] = '\0'; for(int i = 0; i < 10; i ++){ num[0] = i + 48; f(num, n, 0); } delete [] num; return 0; }
22.
判斷一棵樹是不是平衡二叉樹
解決方案:要想知道是不是平衡二叉樹,就得先知道該點左右孩子深度之差,超過二就不是 了

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; struct TreeNode{ int value; TreeNode *left; TreeNode *right; }; TreeNode *creatTreeNode(int m){ TreeNode *node = new TreeNode; node->value = m; node->right = node->left = NULL; return node; } void DestroyTree(TreeNode *root){ if(root != NULL){ TreeNode *l = root->left; TreeNode *r = root->right; delete root; root = NULL; DestroyTree(l); DestroyTree(r); } } void connectTree(TreeNode *root, TreeNode *l, TreeNode *r){ if(root != NULL){ root->left = l; root->right = r; } } bool fun(TreeNode *root, int &depth){ if(root == NULL){ depth = 0; return true; } int l_depth, r_depth; if(fun(root->left, l_depth) && fun(root->right, r_depth)){ int diff = l_depth - r_depth; if(diff <= 1 && diff >= -1){ depth = 1 + (l_depth > r_depth ? l_depth : r_depth); return true; } } return false; } int main(){ TreeNode *node1 = creatTreeNode(1); TreeNode *node2 = creatTreeNode(2); TreeNode *node3 = creatTreeNode(3); TreeNode *node4 = creatTreeNode(4); TreeNode *node5 = creatTreeNode(5); TreeNode *node6 = creatTreeNode(6); TreeNode *node7 = creatTreeNode(7); connectTree(node1, node2, node3); connectTree(node2, node4, node5); connectTree(node3, node7, node6); //connectTree(node5, node7, NULL); int depth = 0; if(fun(node1, depth)) puts("yes"); else puts("no"); printf("%d\n", depth); DestroyTree(node1); return 0; }
23.
統計一個排序數組中某一數字出現的次數
解決方案:兩次二分查找,第一次查詢該數字最左邊位置,第二次最右邊,因為連續,所以差值+1就是該數字個數了
二分查找時,要稍微處理下

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; int a[8] = {1,3,3,3,3,3,3,7}; int len = 8; int getFirstK(int l, int r, int k){ //int l = 0, r = len - 1; if(l > r) return -1; int mid = l + r >> 1; if(a[mid] == k){ if((mid && a[mid - 1] != k) || mid == 0) return mid; else r = mid - 1; }else if(a[mid] < k) l = mid + 1; else r = mid - 1; return getFirstK(l, r, k); } int getLastK(int l, int r, int k){ //int l = 0, r = len - 1; if(l > r) return -1; int mid = l + r >> 1; if(a[mid] == k){ if((mid != len - 1 && a[mid + 1] != k) || mid == len - 1) return mid; else l = mid + 1; }else if(a[mid] < k) l = mid + 1; else r = mid - 1; return getLastK(l, r, k); } int main(){ int first = getFirstK(0, len-1, 2); int last = getLastK(0, len-1, 2); if(first > -1 && last > -1) printf("%d\n", last - first + 1); else puts("no"); return 0; }
24.
一個整型數組里除了兩個數字之外,其他的數字都出現了兩次,求這兩個數字。時間O(n),空間O(1)
解決方案:異或所有元素,求最右邊的1,然后按這情況將數組分為兩組

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; int a[8] = {2,4,3,6,3,2,5,5}; int len = 8; bool is_ok(int num, int cnt){ num = num >> cnt; return (num & 1); } int main(){ int res = 0; for(int i = 0; i < len; i ++) res ^= a[i]; int cnt = 0; while((res & 1) == 0 && cnt < 32){ res = res >> 1; cnt ++; } int ans1 = 0, ans2 = 0; for(int i = 0; i < len; i ++){ if(is_ok(a[i], cnt)) ans1 ^= a[i]; else ans2 ^= a[i]; } printf("%d %d\n", ans1, ans2); return 0; }
25.
輸入一個正整數,打印出所有和為該數的正數序列

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; void printf_n(int l, int r){ for(int i = l; i < r; i ++){ printf("%d ", i); } printf("%d\n", r); } void solve(int n){ int l = 1, r = 2; if(n < 3) return; int mid = 1 + n >> 1; int sum = l + r; while( l < mid){ if(sum == n) printf_n(l, r); while(l < mid && sum > n){ sum -= l; l ++; if(sum == n) printf_n(l, r); } r ++; sum += r; } } int main(){ int n; scanf("%d", &n); solve(n); return 0; }
26.
二叉搜索樹不創建新的結點轉換成雙向鏈表

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; struct TreeNode{ int value; TreeNode *left; TreeNode *right; }; TreeNode *creatTreeNode(int m){ TreeNode *node = new TreeNode; node->value = m; node->right = node->left = NULL; return node; } void DestroyTree(TreeNode *root){ if(root != NULL){ TreeNode *l = root->left; TreeNode *r = root->right; delete root; root = NULL; DestroyTree(l); DestroyTree(r); } } void connectTree(TreeNode *root, TreeNode *l, TreeNode *r){ if(root != NULL){ root->left = l; root->right = r; } } void covertToDoubleList(TreeNode **head, TreeNode **list, TreeNode *root){ //TreeNode *root = tt; root->left = *list; if(NULL != *list) (*list)->right = root; else (*head) = root; (*list) = root; printf("%d ", root->value); } void fun(TreeNode **head, TreeNode **list, TreeNode *root){ if(NULL == root) return; if(NULL != root->left) fun(head, list, root->left); covertToDoubleList(head, list, root); /* root->left = *list; if(NULL != *list) (*list)->right = root; else (*head) = root; (*list) = root; printf("%d ", root->value); */ if(NULL != root->right) fun(head, list, root->right); } void solve(TreeNode *root){ TreeNode *head = new TreeNode(); TreeNode *list = new TreeNode(); head = list = NULL; //if(head == NULL)puts("adsf"); fun(&head, &list, root); puts(""); TreeNode *p = head; while(p != NULL){ printf("%d ", p->value); p = p->right; } puts(""); } int main(){ TreeNode *node1 = creatTreeNode(10); TreeNode *node2 = creatTreeNode(6); TreeNode *node3 = creatTreeNode(14); TreeNode *node4 = creatTreeNode(4); TreeNode *node5 = creatTreeNode(8); TreeNode *node6 = creatTreeNode(12); TreeNode *node7 = creatTreeNode(16); connectTree(node1, node2, node3); connectTree(node2, node4, node5); connectTree(node3, node6, node7); solve(node1); //DestroyTree(node1); return 0; }
27.
找出數組中次數超過一半的數字

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; int a[9] = {1,2,2,3,2,2,5,4,2}; int len = 9; bool check(int num){ int cnt = 0; for(int i = 0; i < len; i ++) if(a[i] == num) cnt ++; if(cnt * 2 <= len) return false; else return true; } void solve(){ int res = a[0]; int cnt = 1; for(int i = 1; i < len; i ++){ if(cnt == 0){ res = a[i]; cnt ++; }else if(a[i] == res) cnt ++; else cnt --; } if(check(res)) puts("yes"); else puts("no"); } int main(){ solve(); return 0; }
28.
給定一個整數,求從1到這整數十進制中1出現的次數
解決方案:
分析(轉)
簡單的方法就是按照給位進行分析
在個位出現1的個數=n/10+(個位=0,0;個位>1,1;個位=1,低0位+1);
十位位出現1的個數=n/100*10+(十位=0,0;十位>1,10,;十位=1,低一位+1);
百位出現1的個數=n/1000*100+(百位=0,0;百位>1,100;百位=1,低兩位+1);
等等
算法的復雜度僅僅和位數有關

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <queue> using namespace std; int f(int a){ if(a == 0) return 1; int num = 1; for(int i = 1; i <= a; i ++) num *= 10; return num; } int solve(int n){ int tmp = n; int len = 0; while(tmp){ tmp /= 10; len ++; } tmp = n; int sum = 0; for(int i = 1; i <= len; i ++){ sum += tmp / f(i) * f(i-1); int t = n / f(i-1) % 10; if(t == 1) sum += n % f(i-1) + 1; else if(t > 1) sum += f(i-1); } return sum; } int main(){ int n; scanf("%d", &n); int t = solve(n); printf("%d\n", t); return 0; }
29.
把數組排成最小的數

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <string> #include <queue> using namespace std; int a[3] = {3,32,321}; const int len = 3; int cmp(const string &s1, const string &s2){ string ss1 = s1 + s2; string ss2 = s2 + s1; return s1 > s2; } int main(){ char s[len+1][10]; string ss[len]; for(int i = 0; i < len; i ++){ sprintf(s[i], "%d", a[i]); ss[i] = s[i]; } sort(ss,ss + len, cmp); for(int i = 0; i < len; i ++) //printf("%s", s[i]); cout<<ss[i]; puts(""); return 0; }
30.
尋找丑數(只包含因子為2 3 5的數)

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <string> #include <queue> using namespace std; int Min(int a, int b, int c){ int x = a < b ? a: b; x = x < c ? x : c; return x; } int getUgly(int n){ if(n <= 0) return 0; int *ugly = new int[n]; ugly[0] = 1; int cnt = 1; int *m2 = ugly; int *m3 = ugly; int *m5 = ugly; while(cnt < n){ int min = Min(*m2 * 2, *m3 * 3, *m5 * 5); ugly[cnt] = min; while(*m2 * 2 <= ugly[cnt]) m2 ++; while(*m3 * 3 <= ugly[cnt]) m3 ++; while(*m5 * 5 <= ugly[cnt]) m5 ++; cnt ++; } int ans = ugly[n - 1]; delete [] ugly; return ans; } int main(){ int n; scanf("%d", &n); int t = getUgly(n); printf("%d\n", t); return 0; }
31.
在字符串中找出第一個只出現一次的字符
解決方案:
先遍歷一次建立hash表,然后查找就行

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <string> #include <queue> using namespace std; int main(){ char s[333]; scanf("%s", s); int hashmap[270]; memset(hashmap, 0, sizeof hashmap); for(int i = 0; s[i]; i ++) hashmap[s[i]] ++; bool f = true; for(int i = 0; s[i]; i ++){ if(hashmap[s[i]] == 1){ printf("%c\n", s[i]); f = false; break; } } if(f) puts("not found"); return 0; }
32.
判斷一個序列是不是某二叉排序樹(二叉搜索樹,二元查找樹)的后序遍歷序列
解決方案:
最后一個結點必為根結點,然后根據二叉排序樹的性質找到它的左右孩子,然后再遞歸查找

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <string> #include <queue> using namespace std; bool check(int *a, int n){ if(a == NULL || n < 1) return false; int root = a[n-1]; int l = 0; for(; l < n - 1; l ++){ if(a[l] > root) break; } int r = l; for(; r < n - 1; r ++) if(a[r] < root) return false; bool left = true; if(l > 0) left = check(a, l); bool right = true; if(r < n - 1) right = check(a+l, n - l + 1); return (left && right); } int main(){ int n; scanf("%d", &n); int *a = new int[n]; for(int i = 0; i < n; i ++){ scanf("%d", a + i); } bool ans = check(a, n); if(ans) puts("yes"); else puts("no"); return 0; }
33.
約瑟夫環問題

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <string> #include <queue> using namespace std; int main(){ int n; scanf("%d", &n); int m; scanf("%d", &m); int last = 0; for(int i = 2; i <= n; i ++) last = (last + m) % i; printf("%d\n", last); return 0; }
34.
輸入兩個整數n和m,從數列1,2.......n中隨意取幾個數,使其和等於m,要求將其中所有的可能組合列出來

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <string> #include <queue> using namespace std; void solve(int n, int m){ if(n < 1 || m < 1) return; if(n > m) n = m; int maxn = 1 << n; for(int i = 1; i < maxn; i ++){ int sum = 0; for(int j = i, k = 1; j; j >>= 1, k ++) if(j&1) sum += k; if(sum == m){ for(int j = i, k = 1; j; j >>= 1, k ++) if(j&1) printf("%d ", k); puts(""); } } } int main(){ int n, m; scanf("%d%d", &n, &m); solve(n, m); return 0; }
35.
將一個整數以字符串輸出

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <string> #include <queue> using namespace std; char *int2str(int n){ char *s = new char; char *p = s; bool f = true; if(n == 0){ *p ++ = '0'; *p ++ = '\0'; return s; }else if(n < 0){ f = false; n = - n; } int len = 0; while(n){ *p ++ = n % 10 + 48; n /= 10; ++ len; } if(!f){ len ++; *p ++ = '-'; } *p ++ = '\0'; //printf("%d %s\n\n", len, s); for(int i = 0; i < len / 2; i ++){ char c = s[i]; s[i] = s[len - i - 1]; s[len - i - 1] = c; } return s; } int main(){ int n; scanf("%d", &n); char *s = int2str(n); printf("%s\n", s); return 0; }
36.
求兩個字符串的最長連續公共子串並返回分別在兩個子串中的位置

#include <cstdio> #include <cstring> #include <stack> #include <set> #include <algorithm> #include <iostream> #include <string> #include <queue> using namespace std; char *lcs(int &index1, int &index2, char *s1, char *s2){ int mat[111][111]; memset(mat, 0, sizeof mat); int maxlen = 0; for(int i = 0; s1[i]; i ++){ for(int j = 0; s2[j]; j ++){ if(s1[i] == s2[j]){ if(i && j){ mat[i][j] = mat[i-1][j-1] + 1; } else mat[i][j] = 1; if(mat[i][j] > maxlen){ maxlen = mat[i][j]; index1 = i; index2 = j; } } } } char *s = new char[maxlen+1]; for(int i = 0; i < maxlen; i ++){ s[i] = s1[index1 - maxlen + i + 1]; } index1 = index1 - maxlen + 1; index2 = index2 - maxlen + 1; s[maxlen] = '\0'; return s; } int main(){ char s1[111], s2[111]; while(~scanf("%s%s", s1, s2)){ int index1, index2; char *s = lcs(index1, index2, s1, s2); printf("%s %d %d\n", s, index1, index2); } return 0; }