二分查找 int search(vector<int>& nums, int target) { int left = 0; int right = nums.size()-1; while(left <= right) { int mid = left + (right-left)/2; if(nums[mid] < target) { left = mid+1; } else if(nums[mid] > target) { right = mid-1; } else { return mid; } } return -1; } 歸併排序(merge sort)或者快速排序(quicksort)和基數排序(radix sort)nlogn 動態數組 擴容拷貝刪除原有內存 利用兩個隊列實現一個棧,以及利用兩個棧來實現一個隊列 讀取和寫入文件,而且要知道如何生成隨機數 void selectKItems(int stream[], int n, int k) { int i; // index for elements in stream[] int reservoir[k]; for (i = 0; i < k; i++) reservoir[i] = stream[i]; srand(time(NULL)); for (; i < n; i++) { int j = rand() % (i+1); if (j < k) reservoir[j] = stream[i]; } printf("Following are k randomly selected items \n"); printArray(reservoir, k); } 每個數均可以被分解成質數的和。 int countPrimes(int n) { vector<bool> prime(n, true); prime[0] = false, prime[1] = false; for (int i = 0; i < sqrt(n); ++i) { if (prime[i]) { for (int j = i*i; j < n; j += i) { prime[j] = false; } } } return count(prime.begin(), prime.end(), true); } 位:bit = num & (1 << x); num ^= 1 << x; 等 數學:Cnk=n! / k!(n-k)! Cnk=Cn-1k+Cn-1k-1 Cnk=Cnn-k Ank=n!/(n-k)! Ann=n! http://www.cs.trincoll.edu/~ram/cpsc110/inclass/conversions.html
廣度優先搜索(breadth-first-search)、深度優先搜索(depth-first-search),以及中序遍歷、後序遍歷和前序遍歷之間的差異。
堆總能找到最大值,但代價就是尋找其餘任何一個值所需的時間都是O(n)。插入和刪除所需的時間依然是O(logn)
字典樹
二叉樹-》二叉搜索樹=》平衡樹/紅黑樹 查找、插入和刪除就能夠在O(log n)html
找下一個 https://leetcode.com/problems/next-permutation void nextPermutation(vector<int>& nums) { int n = nums.size(), k, l; for (k = n - 2; k >= 0; k--) { if (nums[k] < nums[k + 1]) { break; } } if (k < 0) { reverse(nums.begin(), nums.end()); } else { for (l = n - 1; l > k; l--) { if (nums[l] > nums[k]) { break; } } swap(nums[k], nums[l]); reverse(nums.begin() + k + 1, nums.end()); } }
Anm https://leetcode.com/problems/permutations-ii/ vector<vector<int>> permuteUnique(vector<int>& nums) { vector<vector<int>> ret; if(nums.empty()){ return ret; } sort(nums.begin(),nums.end()); //1.排序 每次第一個都會入,若是不排序 跳太重複會用不了 permuteInner(nums,0,ret); return ret; } void permuteInner(vector<int> nums,int stable,vector<vector<int>>& ret) { if(stable==nums.size()-1){ ret.push_back(nums); return; } for(int j=stable;j<nums.size();j++){ //2.跳太重複 if(stable!=j&&nums[j]==nums[stable]){ continue; } //3.至關於前面j位已經排好,求j後面的排序組合,但前面j位能夠是後面的任何一個。交換 swap(nums[stable],nums[j]); permuteInner(nums,stable+1,ret); } }
Cmn 非重複node
vector<vector<int>> subsets(vector<int>& nums) { vector<vector<int>> ret{{}}; ret.push_back(tmp); for(int i=0;i<nums.size();i++){ subsetsInner(nums[i], ret); } return ret; } void subsetsInner(int num,vector<vector<int>>& ret){ int len=ret.size(); for(int i=0;i<len;i++){ vector<int> tmp=ret[i]; tmp.push_back(num); ret.push_back(tmp); } }
Cmn 重複的排序c++
vector<vector<int>> subsetsWithDup(vector<int>& nums) { sort(nums.begin(),nums.end()); vector<vector<int>> ret{{}}; for(int i=0;i<nums.size();i++){ vector<int> tmp(1,nums[i]); while(i<nums.size()-1&&nums[i+1]==nums[i]){ i++; tmp.push_back(nums[i]); } subsetsWithDup2(tmp,ret); } return ret; } void subsetsWithDup2(vector<int>& nums,vector<vector<int>>& ret){ int len=ret.size(); for(int i=0;i<len;i++){ for(int j=1;j<=nums.size();j++){ vector<int> tmp=ret[i]; tmp.insert(tmp.end(),nums.begin(),nums.begin()+j); ret.push_back(tmp); } } }
可重複和算法
vector<vector<int>> combinationSum(vector<int>& candidates, int target) { vector<vector<int>> ret; vector<int> sret; sort(candidates.begin(),candidates.end()); combinationSumInner(candidates,0,target,sret,ret); return ret; } void combinationSumInner(vector<int>& candidates,int begin,int target,vector<int>& sret,vector<vector<int>>& ret){ for(int i=begin;i<candidates.size();i++){ if(target-candidates[i]>0){ sret.push_back(candidates[i]); combinationSumInner(candidates,i,target-candidates[i],sret,ret); sret.erase(sret.end()-1); }else if(target-candidates[i]==0){ sret.push_back(candidates[i]); ret.push_back(sret); sret.erase(sret.end()-1); } } }
不可重複和數組
void combinationSumInner(vector<int>& candidates,int begin,int target,vector<int>& sret,vector<vector<int>>& ret){ for(int i=begin;i<candidates.size();i++){ if(i>begin && candidates[i]==candidates[i-1]) continue; //去重複 if(target-candidates[i]>0&&(i<candidates.size()-1)){ sret.push_back(candidates[i]); combinationSumInner(candidates,i+1,target-candidates[i],sret,ret); //前移 sret.erase(sret.end()-1); }else if(target-candidates[i]==0){ sret.push_back(candidates[i]); ret.push_back(sret); sret.erase(sret.end()-1); } } }
數字加和緩存
void combinationSumInner(int k,int begin,int n,vector<int>& sret,vector<vector<int>>& ret){ for(int i=begin;i<10;i++){ if(n-i>0&&(i<9)&&k>1){ sret.push_back(i); combinationSumInner(k-1,i+1,n-i,sret,ret); //前移 sret.erase(sret.end()-1); }else if(n-i==0&&k==1){ sret.push_back(i); ret.push_back(sret); sret.erase(sret.end()-1); } } }
k-sum問題
轉爲一個和和k-1sum的問題。常規復雜度n^(k-1)
2-sum 首尾指針。或者一個hash 另外一個查加和
3-sum 一個for 兩個首尾。只要後面的
4-sum 2個先緩存,再用2-sum的chahedom
鏈表深拷貝 next和random兩個不一樣指針的拷貝 //把2插入到1中, //l1->next->random = l1->random->next RandomListNode *copyRandomList(RandomListNode *head) { RandomListNode *newHead, *l1, *l2; if (head == NULL) return NULL; for (l1 = head; l1 != NULL; l1 = l1->next->next) { l2 = new RandomListNode(l1->label); l2->next = l1->next; l1->next = l2; } newHead = head->next; for (l1 = head; l1 != NULL; l1 = l1->next->next) { if (l1->random != NULL) l1->next->random = l1->random->next; } for (l1 = head; l1 != NULL; l1 = l1->next) { l2 = l1->next; l1->next = l2->next; if (l2->next != NULL) l2->next = l2->next->next; } return newHead; } //用map把新舊映射後,random對應下 public RandomListNode copyRandomList(RandomListNode head) { if (head == null) return head; RandomListNode newHead = new RandomListNode(head.label); RandomListNode oldp = head.next; RandomListNode newp = newHead; Map<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>(); //採用map結構來存儲對應的關係 map.put(newp, head); while (oldp != null) {//複製舊的鏈表 RandomListNode newTemp = new RandomListNode(oldp.label); map.put(newTemp, oldp); newp.next = newTemp; newp=newp.next; oldp=oldp.next; } oldp=head; newp=newHead; while (newp!=null){//複製random指針 newp.random=map.get(newp).random;//取得舊節點的random指針 newp=newp.next; oldp=oldp.next; } return head; }
鏈表翻轉 ListNode* reverseList(ListNode* head) { ListNode* cur = NULL; while (head) { ListNode* next = head -> next; head -> next = cur; cur = head; head = next; } return cur; } ListNode* reverseList(ListNode* head) { if (!head || !(head -> next)) { return head; } ListNode* node = reverseList(head -> next); head -> next -> next = head; head -> next = NULL; return node; }
鏈表去重。要用刪除後面節點。head不須要處理
窗口 https://blog.csdn.net/whdAlive/article/details/81132383
迴文的Manacher算法。
ide
KMP:優化
dijkstrasui
sptSet 鄰接表 距離值 0和最大 a) 選擇sptSet中不存在的頂點u並具備最小距離值。 b)包括u到sptSet。 c)更新u的全部相鄰頂點的距離值。要更新距離值,請遍歷全部相鄰頂點。對於每一個相鄰頂點v,若是u(來自源)和邊緣uv的權重的距離值之和小於v的距離值,則更新v的距離值。 #include <stdio.h> #include <limits.h> // Number of vertices in the graph #define V 9 int minDistance(int dist[], bool sptSet[]) { // Initialize min value int min = INT_MAX, min_index; for (int v = 0; v < V; v++) if (sptSet[v] == false && dist[v] <= min) min = dist[v], min_index = v; return min_index; } int printSolution(int dist[], int n) { printf("Vertex Distance from Source\n"); for (int i = 0; i < V; i++) printf("%d tt %d\n", i, dist[i]); } void dijkstra(int graph[V][V], int src) { int dist[V]; bool sptSet[V]; for (int i = 0; i < V; i++) dist[i] = INT_MAX, sptSet[i] = false; dist[src] = 0; // Find shortest path for all vertices for (int count = 0; count < V-1; count++) { int u = minDistance(dist, sptSet); sptSet[u] = true; for (int v = 0; v < V; v++) if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u]+graph[u][v] < dist[v]) dist[v] = dist[u] + graph[u][v]; } // print the constructed distance array printSolution(dist, V); } // driver program to test above function int main() { /* Let us create the example graph discussed above */ int graph[V][V] = {{0, 4, 0, 0, 0, 0, 0, 8, 0}, {4, 0, 8, 0, 0, 0, 0, 11, 0}, {0, 8, 0, 7, 0, 4, 0, 0, 2}, {0, 0, 7, 0, 9, 14, 0, 0, 0}, {0, 0, 0, 9, 0, 10, 0, 0, 0}, {0, 0, 4, 14, 10, 0, 2, 0, 0}, {0, 0, 0, 0, 0, 2, 0, 1, 6}, {8, 11, 0, 0, 0, 0, 1, 0, 7}, {0, 0, 2, 0, 0, 0, 6, 7, 0} }; dijkstra(graph, 0); return 0; }
Floyd
多源最短路徑
最開始只容許通過 1 號頂點進行中轉,接下來只容許通過 1 和 2 號頂點進行中轉。
#include <bits/stdc++.h> using namespace std; #define V 4 #define INF 99999 void printSolution(int dist[][V]); void floydWarshall (int graph[][V]) { int dist[V][V], i, j, k; for (i = 0; i < V; i++) for (j = 0; j < V; j++) dist[i][j] = graph[i][j]; for (k = 0; k < V; k++) { // Pick all vertices as source one by one for (i = 0; i < V; i++) { // Pick all vertices as destination for the // above picked source for (j = 0; j < V; j++) { if (dist[i][k] + dist[k][j] < dist[i][j]) dist[i][j] = dist[i][k] + dist[k][j]; } } } // Print the shortest distance matrix printSolution(dist); } /* A utility function to print solution */ void printSolution(int dist[][V]) { cout<<"The following matrix shows the shortest distances" " between every pair of vertices \n"; for (int i = 0; i < V; i++) { for (int j = 0; j < V; j++) { if (dist[i][j] == INF) cout<<"INF"<<" "; else cout<<dist[i][j]<<" "; } cout<<endl; } } // Driver code int main() { int graph[V][V] = { {0, 5, INF, 10}, {INF, 0, 3, INF}, {INF, INF, 0, 1}, {INF, INF, INF, 0} }; // Print the solution floydWarshall(graph); return 0; }
DFS void Graph::addEdge(int v, int w) { adj[v].push_back(w); // Add w to v’s list. } void Graph::DFSUtil(int v, bool visited[]) { // Mark the current node as visited and // print it visited[v] = true; cout << v << " "; // Recur for all the vertices adjacent // to this vertex list<int>::iterator i; for (i = adj[v].begin(); i != adj[v].end(); ++i) if (!visited[*i]) DFSUtil(*i, visited); } // DFS traversal of the vertices reachable from v. // It uses recursive DFSUtil() void Graph::DFS(int v) { // Mark all the vertices as not visited bool *visited = new bool[V]; for (int i = 0; i < V; i++) visited[i] = false; // Call the recursive helper function // to print DFS traversal DFSUtil(v, visited); } void Graph::addEdge(int v, int w) { adj[v].push_back(w); // Add w to v’s list. } void Graph::DFSUtil(int v, bool visited[]) { // Mark the current node as visited and // print it visited[v] = true; cout << v << " "; // Recur for all the vertices adjacent // to this vertex list<int>::iterator i; for (i = adj[v].begin(); i != adj[v].end(); ++i) if (!visited[*i]) DFSUtil(*i, visited); } // DFS traversal of the vertices reachable from v. // It uses recursive DFSUtil() void Graph::DFS(int v) { // Mark all the vertices as not visited bool *visited = new bool[V]; for (int i = 0; i < V; i++) visited[i] = false; // Call the recursive helper function // to print DFS traversal DFSUtil(v, visited); } 應用 word search class GFG { // Let the given dictionary be following static final String dictionary[] = { "GEEKS", "FOR", "QUIZ", "GUQ", "EE" }; static final int n = dictionary.length; static final int M = 3, N = 3; static boolean isWord(String str) { // Linearly search all words for (int i = 0; i < n; i++) if (str.equals(dictionary[i])) return true; return false; } // A recursive function to print all words present on boggle static void findWordsUtil(char boggle[][], boolean visited[][], int i, int j, String str) { visited[i][j] = true; str = str + boggle[i][j]; // If str is present in dictionary, then print it if (isWord(str)) System.out.println(str); // Traverse 8 adjacent cells of boggle[i][j] for (int row = i - 1; row <= i + 1 && row < M; row++) for (int col = j - 1; col <= j + 1 && col < N; col++) if (row >= 0 && col >= 0 && !visited[row][col]) findWordsUtil(boggle, visited, row, col, str); str = "" + str.charAt(str.length() - 1); visited[i][j] = false; } // Prints all words present in dictionary. static void findWords(char boggle[][]) { // Mark all characters as not visited boolean visited[][] = new boolean[M][N]; // Initialize current string String str = ""; // Consider every character and look for all words // starting with this character for (int i = 0; i < M; i++) for (int j = 0; j < N; j++) findWordsUtil(boggle, visited, i, j, str); } } BFS void Graph::BFS(int s) { bool *visited = new bool[V]; for(int i = 0; i < V; i++) visited[i] = false; list<int> queue; visited[s] = true; queue.push_back(s); list<int>::iterator i; while(!queue.empty()) { s = queue.front(); cout << s << " "; queue.pop_front(); for (i = adj[s].begin(); i != adj[s].end(); ++i) { if (!visited[*i]) { visited[*i] = true; queue.push_back(*i); } } } }
拓撲排序 修改 DFS以查找圖的拓撲排序。在 DFS中,咱們從頂點開始,首先打印它,而後遞歸調用DFS做爲其相鄰頂點。在拓撲排序中,咱們使用臨時堆棧。咱們不當即打印頂點,咱們首先遞歸調用其全部相鄰頂點的拓撲排序,而後將其推送到堆棧。最後,打印堆棧的內容。請注意,只有當頂點的全部相鄰頂點(及其相鄰頂點等)已經在堆棧中時,頂點纔會被推送到堆棧。 void Graph::topologicalSortUtil(int v, bool visited[], stack<int> &Stack) { // Mark the current node as visited. visited[v] = true; // Recur for all the vertices adjacent to this vertex list<int>::iterator i; for (i = adj[v].begin(); i != adj[v].end(); ++i) if (!visited[*i]) topologicalSortUtil(*i, visited, Stack); // Push current vertex to stack which stores result Stack.push(v); } void Graph::topologicalSort() { stack<int> Stack; // Mark all the vertices as not visited bool *visited = new bool[V]; for (int i = 0; i < V; i++) visited[i] = false; // Call the recursive helper function to store Topological // Sort starting from all vertices one by one for (int i = 0; i < V; i++) if (visited[i] == false) topologicalSortUtil(i, visited, Stack); // Print contents of stack while (Stack.empty() == false) { cout << Stack.top() << " "; Stack.pop(); } }
最小生成樹 primer:和最短路徑差很少,每次找聯通的定點 Kruskal:先找最小邊各自鏈接 1.按重量的非遞減順序對全部邊緣進行排序。 2.選擇最小的邊緣。檢查它是否造成了到目前爲止造成的生成樹的循環。若是沒有造成循環,則包括此邊。不然,丟棄它。 3.重複步驟#2,直到生成樹中有(V-1)條邊。
還路判斷
DFS + 是否在前面路徑上(visited+rectrace)
bool Graph::isCyclicUtil(int v, bool visited[], bool *recStack) { if(visited[v] == false) { // Mark the current node as visited and part of recursion stack visited[v] = true; recStack[v] = true; // Recur for all the vertices adjacent to this vertex list<int>::iterator i; for(i = adj[v].begin(); i != adj[v].end(); ++i) { if ( !visited[*i] && isCyclicUtil(*i, visited, recStack) ) return true; else if (recStack[*i]) return true; } } recStack[v] = false; // remove the vertex from recursion stack return false; } bool Graph::isCyclic() { // Mark all the vertices as not visited and not part of recursion // stack bool *visited = new bool[V]; bool *recStack = new bool[V]; for(int i = 0; i < V; i++) { visited[i] = false; recStack[i] = false; } // Call the recursive helper function to detect cycle in different // DFS trees for(int i = 0; i < V; i++) if (isCyclicUtil(i, visited, recStack)) return true; return false; }
另外一種:不相交集
int find(int parent[], int i) { if (parent[i] == -1) return i; return find(parent, parent[i]); } // A utility function to do union of two subsets void Union(int parent[], int x, int y) { int xset = find(parent, x); int yset = find(parent, y); if(xset != yset) { parent[xset] = yset; } } int isCycle( Graph* graph ) { // Allocate memory for creating V subsets int *parent = new int[graph->V * sizeof(int)]; // Initialize all subsets as single element sets memset(parent, -1, sizeof(int) * graph->V); // Iterate through all edges of graph, find subset of both // vertices of every edge, if both subsets are same, then // there is cycle in graph. for(int i = 0; i < graph->E; ++i) { int x = find(parent, graph->edge[i].src); int y = find(parent, graph->edge[i].dest); if (x == y) return 1; Union(parent, x, y); } return 0; }
割點和橋
割點:low[v] >= dnf[u]
橋:low[v] > dnf[u] 就說明V-U是橋
01揹包
ansx = max(ansx-1,ansx-1]+v[x]);
只須要一層.這裏若是不逆序,每次算完的新的i的dp[j]會把以前的i-1的dp[j]覆蓋。致使i重複計算,被用了屢次。好比揹包V=8.2-3,1-2的物品
for(int i=1;i<=n;i++) for(int j=v;j>=volume[i];j--) dp[j]=max(dp[j],dp[j-volume[i]]+value[i]);
初始化:
裝滿的 ---只有0能裝滿0,其餘的初始化爲負無窮
不須要裝滿的-----全部的初始都爲0
徹底揹包:每件 物品 能夠取無限件
for(int i=1;i<=n;i++) for(int j=volume[i];j<=v;j++) dp[j]=max(dp[j],dp[j-volume[i]]+value[i]);
多重揹包:
max{dp[j-kvolume[i]]+kvalue[i]} 0<=k<=num[i]
可是可優化:二進制組合數,不用k個。若是不用二進制,咱們須要拆分紅9個物品,利用二進制,咱們拆分紅比9小的二進制數1 2 4 8,便可。
最小編輯距離,兩個串通過多少改變同樣。不同要麼添加/刪除/交換
if (word1[i - 1] == word2[j - 1]) edi = edi - 1;
else edi = min(min(edi + 1, edi - 1 + 1), edi - 1 + 1);
LIS(最長遞增順序)
普通DP:
for (int j = 0; j < i; ++j) { if (nums[i] > nums[j]) { dp[i] = max(dp[i], dp[j] + 1); } }
咱們先創建一個數組ends,把首元素放進去,而後比較以後的元素,若是遍歷到的新元素比ends數組中的首元素小的話,替換首元素爲此新元素,若是遍歷到的新元素比ends數組中的末尾元素還大的話,將此新元素添加到ends數組末尾(注意不覆蓋原末尾元素)。若是遍歷到的新元素比ends數組首元素大,比尾元素小時,此時用二分查找法找到第一個不小於此新元素的位置,覆蓋掉位置的原來的數字,以此類推直至遍歷完整個nums數組
int lengthOfLIS(vector<int>& nums) { if (nums.empty()) return 0; vector<int> ends{nums[0]}; for (auto a : nums) { if (a < ends[0]) ends[0] = a; else if (a > ends.back()) ends.push_back(a); else { int left = 0, right = ends.size(); while (left < right) { int mid = left + (right - left) / 2; if (ends[mid] < a) left = mid + 1; else right = mid; } ends[right] = a; } } return ends.size(); }
多模式匹配。相似KMP,把模式構形成帶fail(kmp的next)基樹。
A*啓發式
計算過的加入close list待計算openlist 每次找最小的(起點代價+終點預估代價)