Data structure | 5. Sorting and searching

Sorting algorithms can be classified into stable sorting and unstable sorting according to whether they are stable or no...
1.1 insert sort
1.2 bubble sorting
1.3 merge sort
1.4 implementation of stable sorting code
2.1 select sort
2.2 quick sort
2.3 implementation of unstable sorting code
2.4 optimization of quick sort
3.1 binary search
3.2 binary search code implementation
3.3 three point search: solve the extreme value of concave convex function
4.1 conflict generation process simulation
4.2 conflict handling methods
4.3 hash table code implementation
Leetcode 1. Sum of two numbers
Leetcode 3. Longest substring without duplicate characters
Leetcode 4. Find the median of two positively ordered arrays
Leetcode 21. Merge two ordered linked lists
Leetcode 35. Search for inserted locations
Leetcode 38. Appearance series
Leetcode 88. Merge two ordered arrays
Leetcode 217. There are duplicate elements
Leetcode 219. Repeating Element II
Leetcode 278. First wrong version
Leetcode 349. Intersection of two arrays
Leetcode 350. Intersection of two arrays II
Leetcode 374. Guess the size of the number
Leetcode 378. The K-th smallest element in an ordered matrix

Sorting algorithms can be classified into stable sorting and unstable sorting according to whether they are stable or not; If all the input data needs to be loaded into memory for sorting, it is internal sorting. If the amount of data is too large to be loaded into memory, the sorting that must be completed on disk or tape is called external sorting.
For example, there is a 30G data that needs to be loaded into memory when the program runs. Bubble and insert sorting are internal sorting. Assuming that the memory is only 16G, so bubble and insert cannot be loaded, so we need to use external sorting - merge sorting. First load 15G into internal memory, and then put the data on disk, Then load another 15G of data into memory for sorting.

1. Stable sort (insert, bubble, merge)

1.1 insert sort

1.1.1 time complexity

O ( n 2 ) O(n^2) O(n2)

1.1.2 formula

  1. Divide the array into "sorted area" and "to be sorted area"
  2. Insert the element after the sorted area forward into the sorted area
  3. Until there are no elements in the "to be sorted area"

1.1.3 process example

1.2 bubble sorting

1.2.1 time complexity

O ( n 2 ) O(n^2) O(n2)

1.2.2 formula

  1. Divide the array into "sorted area" and "to be sorted area"
  2. Scan the "to be sorted area" from beginning to end. If the front element is larger than the rear element, it will be exchanged
  3. In each round, the largest in the "to be sorted area" will be placed at the beginning of the "sorted area"
  4. Until there are no elements in the "to be sorted area"

1.2.3 process example

1.2.4 optimization tips

When there is no exchange operation in a round of bubbling process, the whole bubbling sorting process is ended.

1.3 merge sort

1.3.1 time complexity

The idea of divide and conquer is adopted, and the time complexity is O ( n l o g n ) O(nlogn) O(nlogn), with 2 as the bottom, also known as two-way merge sort.

1.3.2 process example






Merge sort can also have K K K-way merging, each time divided into K K K small problems will be realized with the help of heap.

1.4 implementation of stable sorting code

/************************************************************************* > File Name: stable_sort.c > Author: Maureen > Mail: [email protected] > Created Time: 17:18:05, September 26, 2021 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h> #define COLOR(msg, code) "\033[0;" #code "m" msg "\033[0m" #define YELLOW(msg) COLOR(msg, 33) #define swap(a, b) {\ __typeof(a) _temp = a;\ a = b;\ b = _temp;\ } void output(int *arr, int n) { printf("["); for (int i = 0; i < n; i++) { printf(" %d", arr[i]); } printf("]"); return ; } #define TEST(arr, n, func, args...) {\ int *nums = (int *)malloc(sizeof(int) * n);\ memcpy(nums, arr, sizeof(int) * n);\ output(nums, n);\ printf("\n%s = ", #func);\ long long begin = clock();\ func(args);\ long long end = clock();\ output(nums, n);\ printf(YELLOW("(%lld ms)") "\n", (end - begin) * 1000 / CLOCKS_PER_SEC);\ free(nums);\ } /* * Insert sort */ void insert_sort(int *arr, int n) { for (int i = 1; i < n; i++) { int tmp = arr[i]; int j; for (j = i; j > 0 && arr[j - 1] > tmp; j--) { arr[j] = arr[j - 1]; } arr[j] = tmp; } return ; } /* * Bubble sorting */ void bubble_sort(int *arr, int n) { int times = 1; //Mark whether the exchange has occurred. If there is no exchange in a certain sort, the array has been ordered for (int i = 1; i <= n && times; i++) { //Number of sortings times = 0; for (int j = 0; j < n - i; j++) { if (arr[j] < arr[j + 1]) continue; swap(arr[j], arr[j + 1]); times++; } } return ; } /* * Merge sort * Merge sort adopts divide and conquer idea, so recursive programming idea is used */ void merge_sort(int *arr, int left, int right) { if (right - left <= 1) { //Termination condition: there are only 2 elements in each group if (right - left == 1 && arr[right] < arr[left]) { swap(arr[left], arr[right]); } return ; } int mid = (left + right) >> 1; merge_sort(arr, left, mid); merge_sort(arr, mid + 1, right); //Merge two ordered parts, that is, merge two ordered arrays int *temp = (int *)malloc(sizeof(int) * (right - left + 1)); int p1 = left; int p2 = mid + 1; int k = 0;//Growth subscript of temp array while (p1 <= mid || p2 <= right) { if (p2 > right || (p1 <= mid && arr[p1] <= arr[p2])) { temp[k++] = arr[p1]; p1++; } else { temp[k++] = arr[p2]; p2++; } } //Copy the contents of temporary data back to the upper array memcpy(arr + left, temp, sizeof(int) * (right - left + 1)); free(temp); return ; } void rand_int(int *arr, int n) { while (n--) arr[n] = rand() % 100; return ; } int main() { srand(time(0)); #define max_op 20 int arr[max_op]; rand_int(arr, max_op); //Randomly generate values for arrays TEST(arr, max_op, insert_sort, nums, max_op); TEST(arr, max_op, bubble_sort, nums, max_op); TEST(arr, max_op, merge_sort, nums, 0, max_op - 1); #undef max_op return 0; }

When the amount of data > 1000, you can basically see the time difference of the three sorting methods.

2. Unstable sorting

2.1 select sort

2.1.1 time complexity

Find the minimum value of the "to be sorted area", you need to n − 1 n - 1 n − 1, the number of exchanges is 1, and the time complexity is O ( n 2 ) O(n^2) O(n2). For a set of basically ordered arrays, selective sorting is faster than bubble sorting because it reduces the number of exchanges.

2.1.2 formula

  1. Divide the array into "sorted area" and "to be sorted area"
  2. In each round, select the smallest element from the "to be sorted area" and put it at the end of the "sorted area"
  3. Until there are no elements in the "to be sorted area"

2.1.3 process example


The elements in the array after the next round of sorting process:

The elements in the array after the next three rounds of sorting:

2.1.4 why is selective sorting unstable?

For example, 5 2 3 5 1, after a round of selection sorting, becomes 1 2 3 5 5, and the relative position of the two 5 has changed, so it is an unstable sorting.

2.2 quick sort

2.2.1 time complexity

Normally O ( n l o g n ) O(nlogn) O(nlogn), but degradation may occur, so that the time complexity is O ( n 2 ) O(n^2) O(n2), such as a group of integers in complete reverse order, will be sorted from small to large, so the pointer will be exchanged every time it moves, which is similar to selective sorting. Similar to the merge algorithm, the divide and conquer algorithm is also used.

2.2.2 process example

  1. Select cardinality, usually the first element of the array, that is, the element with subscript 0. Logically speaking, position 0 is empty.
  2. Move the pointer forward, look forward from the back of the array, and find the first value less than the current cardinality.
  3. When the header is assigned, the pointer moves back, and the value less than the cardinality is placed at the position pointed by the header pointer, that is, position 0. Logically speaking, the position pointed by the tail pointer is empty.
  4. Tail assignment: move the pointer forward and backward, find the first value greater than the reference value, put it at the position pointed by the tail pointer, and move the tail pointer forward.

    Repeat steps 2 to 4:




    When the head pointer and the tail pointer coincide, the position where the reference value should be found.

    The array becomes basically ordered. According to the current benchmark value, the parts in front of the benchmark value are less than the benchmark value, and the parts behind the benchmark value are greater than or equal to the benchmark value. This is called a partition operation.

2.3 implementation of unstable sorting code

/************************************************************************* > File Name: 002.unstable_sort.c > Author: Maureen > Mail: [email protected] > Created Time: I 9 / 27 18:17:17 2021 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h> #define COLOR(msg, code) "\033[0;" #code "m" msg "\033[0m" #define YELLOW(msg) COLOR(msg, 33) #define swap(a, b) {\ __typeof(a) _temp = a;\ a = b;\ b = _temp;\ } #define TEST(arr, n, func, args...) {\ int *nums = (int *)malloc(sizeof(int) * n);\ memcpy(nums, arr, sizeof(int) * n);\ output(nums, n);\ printf("\n%s = ", #func);\ long long begin = clock();\ func(args);\ long long end = clock();\ output(nums, n);\ printf(YELLOW("(%lld ms)") "\n", (end - begin) * 1000 / CLOCKS_PER_SEC);\ free(nums);\ } /* * Select sort */ void selected_sort(int *arr, int n) { for (int i = 0; i < n - 1; i++) { //Number of sortings n-1 int ind = i; for (int j = i + 1; j < n; j++) { //Find the minimum value of the area to be sorted if (arr[ind] > arr[j]) ind = j; } swap(arr[ind], arr[i]); } } /* * Quick sort */ void quick_sort(int *arr, int left, int right) { if (left > right) return ; int x = left, y = right, z = arr[x]; //z is the reference value while (x < y) { //Head and tail pointers do not coincide while (x < y && arr[y] > z) y--; //The tail pointer moves forward to find a value smaller than z if (x < y) arr[x++] = arr[y]; //Put the value smaller than z pointed by the tail pointer to the position pointed by the head pointer while (x < y && arr[x] < z) x++; //The head pointer moves forward to find a value greater than z if (x < y) arr[y--] = arr[x]; //Put the value larger than z pointed by the head pointer at the position pointed by the tail pointer } arr[x] = z; //The benchmark value is placed. The array is basically in order. The left is smaller than the benchmark value and the right is larger than the benchmark value quick_sort(arr, left, x - 1);//Recursively process the left part of the reference value quick_sort(arr, x + 1, right); //Recursively process the right part of the reference value return ; } void output(int *arr, int n) { printf("["); for (int i = 0; i < n; i++) { printf(" %d", arr[i]); } printf("]"); } int main() { srand(time(0)); #define max_op 20 int arr[max_op]; for (int i = 0; i < max_op; i++) { arr[i] = rand() % 100; } TEST(arr, max_op, selected_sort, nums, max_op); TEST(arr, max_op, quick_sort, nums, 0, max_op - 1); #undef max_op return 0; }

2.4 optimization of quick sort

For a group of arrays in complete reverse order, such as 5 4 3 2 1, if you want to sort from small to large, the head and tail pointers will be exchanged every time you move, which reduces the time complexity to O ( n 2 ) O(n^2) O(n2), which behaves in a similar way to selection sorting. The reason why the pointer will be exchanged every time it moves is that the selected benchmark value is the first element, so it needs to be exchanged every step.

Optimize fast exhaust:

/************************************************************************* > File Name: 003.quick_sort_optimized.c > Author: Maureen > Mail: [email protected] > Created Time: I 9 / 27 18:50:06 2021 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <time.h> #define max_n 20 #define swap(a, b) {\ __typeof(a) _temp = a;\ a = b;\ b = _temp;\ } void quick_sort(int *arr, int left, int right) { //1. For the optimization of the benchmark value, the middle value of the "to be sorted interval" is used as the benchmark value //2. Change recursion into half loop and half recursion while (left < right) { int x = left, y = right, z = arr[(left + right) >> 1]; do { //The left half is achieved by looping while (x <= y && arr[x] < z) x++; while (x <= y && arr[y] > z) y--; if (x <= y) { swap(arr[x], arr[y]);//Find the one smaller than the reference value and the one larger than the reference value, and exchange the two values x++, y--; } } while (x <= y); quick_sort(arr, x, right); right = y; } return ; } int arr[max_n + 5]; void output(int *arr, int n) { printf("arr = ["); for (int i = 0; i < n; i++) { printf(" %d", arr[i]); } printf("]\n"); return ; } int main() { srand(time(0)); for (int i = 0; i < max_n; i++) { arr[i] = max_n - i; //Completely inverted array } output(arr, max_n); long long begin = clock(); quick_sort(arr, 0, max_n - 1); long long end = clock(); output(arr, max_n); printf("(cost %lld ms)\n", (end - begin) * 1000 / CLOCKS_PER_SEC); return 0; }
3. Binary search and ternary search

3.1 binary search

Premise: the sequence to be searched is monotonic.
Time complexity: O ( l o g n ) O(logn) O(logn), logarithm based on 2.

3.1.1 special case 1: a pile of 1, a pile of 0, find the position of the last 1

Abstract model: 1 to meet a certain characteristic, 0 means that it does not meet a certain requirement.

General binary search:

Areas to be modified:

  1. To avoid dead loops, the mid value should also be adjusted (rounded up)
  2. The value pointed to by the current mid may be a solution, so the value pointed to by the mid cannot be discarded;
  3. When all arrays are 0, the header pointer points to 0, which is easy to cause ambiguity. Whether it is not found or itself is 0, so you can point the header pointer to the virtual header at the beginning, which is - 1 logically.

Therefore, the mid and min are adjusted as follows:

3.1.2 special case 2: a pile of 0, a pile of 1, find the position of the first 1

The nature of binary search needs to be guaranteed:

  1. Arrays are monotonic
  2. The discarded part does not contain possible solutions

General binary search:

Adjustment: the virtual tail pointer max, if all are 0, avoids programming ambiguity and points to the next position of the real element.

3.2 binary search code implementation

/************************************************************************* > File Name: 004.binary_search.c > Author: Maureen > Mail: [email protected] > Created Time: I 9 / 27 19:40:20 2021 ************************************************************************/ #include <stdio.h> #define P(func) {\ printf("%s = %d\n", #func, func);\ } /* * The most basic binary search */ int binary_search_v1(int *arr, int n, int x) { int head = 0, tail = n - 1, mid; while (head <= tail) { mid = (head + tail) >> 1; if (arr[mid] == x) return mid; if (arr[mid] < x) head = mid + 1; else tail = mid - 1; } return -1; } /* * Special case 1: 1111100000 (find the location where the last 1 appears) */ int binary_search_v2(int *arr, int n) { int head = -1; //Tip: head pointer to virtual head int tail = n - 1; int mid; while (head < tail) { mid = (head + tail + 1) >> 1; //!!! Particular attention if (arr[mid] == 1) head = mid; else tail = mid - 1; } return head; } /* * Special case 2: 0000011111 (find the position where the first 1 appears) */ int binary_search_v3(int *arr, int n) { int head = 0; int tail = n; int mid; while (head < tail) { mid = (head + tail) >> 1; if (arr[mid] == 1) tail = mid; else head = mid + 1; } return head == n ? -1 : head; } int main() { int arr1[10] = ; int arr2[10] = ; int arr3[10] = ; P(binary_search_v1(arr1, 10, 7)); P(binary_search_v2(arr2, 10)); P(binary_search_v3(arr3, 10)); return 0; }

3.3 three point search: solve the extreme value of concave convex function

Trisection search can be used to solve the problem of extremum of concave convex function.

m1 and m2 keep approaching the result value to be obtained.

Both three-point search and two-point search are l o g n logn logn level, but binary search is more efficient. The so-called dichotomy and trisection are to divide the scale of the original problem. Dichotomy search is to divide the scale of the original problem equally. Each time, the scale of the original problem can be reduced 1 / 2 1/2 1/2; One third search can reduce the scale of the original problem 1 / 3 1/3 1/3.

3.3.1 application

#include <stdio.h> #define EPS 1e-10 int a, b, c; double equation(int x) { return a * x * x + b * x + c; } double ternary_search1(double l, double r) { while (r - l > EPS) { double m1 = l + (r - l) / 3; double m2 = r - (r - l) / 3; if (equation(m1) < equation(m2)) { l = m1; } else { r = m2; } } return r; } double ternary_search2(double l, double r) { while (r - l > EPS) { double mid = (l + r) / 2; double midmid = (mid + r) / 2; double mid_val = equation(mid); double mid_mid_val = equation(midmid); //printf("%lf %lf\n", mid_val, mid_mid_val); if (mid_val < mid_mid_val) { l = mid; } else { r = midmid; } } return r; } int main() { scanf("%d%d%d", &a, &b, &c); double ans1 = ternary_search1(-100, 100); double ans2 = ternary_search2(-100, 100); double equation_result = equation(ans1); printf("ans1 = %lf, ans2 = %lf, equation_result = %lf\n",ans1, ans2, equation_result); return 0; }
4. Hash table

A hash table is a data structure.

The characteristic of array is to index the value through array subscript, and the time complexity is O ( 1 ) O(1) O(1), but only a value of integer type can be mapped to another value. The hash table structure can map any type of value into an array subscript of integer type, store the value in the subscript, and the search time complexity is approaching O ( 1 ) O(1) O(1).

The structure of the hash table is stored in a sequential table. Mapping any type to an integer value needs to be used to the hash function.

Hash structure has two important components: hash function and conflict handling method.

The structure definition and order representation of hash table are similar.

4.1 conflict generation process simulation




At this point, 7 7 % 16 = 7 7 and 7 should be placed at the position with the subscript 7, but there are already several at this position, which leads to conflict and conflict handling.

4.2 conflict handling methods

  1. Open address method (continue to explore in the future)
  2. Zipper method (store a linked list in the current position)
  3. Hashing method (design more hashing methods, conflict occurs through the first hash function, and then try the second hash function, etc.)
  4. Establish public overflow area

4.3 hash table code implementation

/************************************************************************* > File Name: 005.hash_table.c > Author: Maureen > Mail: [email protected] > Created Time: II 9 / 28 12:16:51 2021 ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> //The string is hashed, and the zipper method is used for conflict handling /* * Structure definition of node */ typedef struct Node { char *str; struct Node *next; } Node; typedef struct HashTable { //The hash table uses a sequential table, and the first address of the linked list is stored in each position Node **data; //Continuous storage space stores the values of nodes int size; } HashTable; /* * Initialization of linked list nodes */ Node *init_node(char *str, Node *head) { Node *p = (Node *)malloc(sizeof(Node)); p->str = strdup(str); //strdup copies the incoming string, first dynamically applies for a space, stores the incoming string, and then returns the first address of the copied string p->next = head; return p; } /* * Initialization of hash table */ HashTable *init_hashTable(int n) { HashTable *h = (HashTable *)malloc(sizeof(HashTable)); h->size = n << 1; //To improve the efficiency of hash tables, you usually double the capacity. In fact, you can't store the number function of capacity h->data = (Node **)calloc(h->size, sizeof(Node *)); //During initialization, each location of the hash table stores the first address of the linked list, which is empty, so calloc is used for space development return h; } /* * A hash function that hashes a string */ int BKDRHash(char *str) { int seed = 31, hash = 0; for (int i = 0; str[i]; i++) { hash = hash * seed + str[i]; } return hash & 0x7fffffff;//Ensure that the result is an integer because the hash may be negative } /* * Insert operation of hash table */ int insert(HashTable *h, char *str) { int hash = BKDRHash(str); int ind = hash % h->size; h->data[ind] = init_node(str, h->data[ind]); //String encapsulated as node return 0; } /* * Lookup operation of hash table */ //Check whether the target value is stored in the location according to the subscript of the value to be found mapped by the hash function int search(HashTable *h, char *str) { int hash = BKDRHash(str); int ind = hash % h->size; Node *p = h->data[ind]; //The ind position is the first address of the linked list while (p && strcmp(p->str, str)) p = p->next; return p != NULL; //String found if p is not empty } void clear_node(Node *node) { if (node == NULL) return ; Node *p = node; Node *q; while (p) { q = p->next; free(p->str); //Because p - > STR is created using strdup, it needs to be released actively free(p); p = q; } return ; } void clear_hashTable(HashTable *h) { if (h == NULL) return ; for (int i = 0; i < h->size; i++) { clear_node(h->data[i]); } free(h->data); free(h); return ; } int main() { int op; #define max_n 100 char str[max_n + 5] = ; HashTable *h = init_hashTable(max_n + 5); while (~scanf("%d%s", &op, str)) { switch (op) { case 0 : printf("insert %s to hash table\n", str); insert(h, str); break; case 1: printf("search %s from HashTable result = %d\n", str, search(h, str)); break; } } #undef max_n clear_hashTable(h); return 0; }
5. Related topics subjectdifficulty1. Sum of two numbersEasy3. Longest substring without repeated charactersMedium4. Find the median of two positively ordered arraysHard21. Merge two ordered linked listsEasy35. Search insertion positionEasy38. Appearance seriesMedium88. Merge two ordered arraysEasy217. There are duplicate elementsEasy219. Duplicate Element II existsEasy278. First wrong versionEasy349. Intersection of two arraysEasy350. Intersection of two arrays IIEasy374. Guess the size of the numberEasy378. The K-th smallest element in an ordered matrixMedium

Leetcode 1. Sum of two numbers

[ideas]

Use hash table to speed up lookup t a r g e t − n u m s [ i ] target - nums[i] Process of target − nums[i]

[Code]

class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int, int> hashtable; for (int i = 0; i < nums.size(); i++) { if (hashtable.count(target - nums[i])) { return ; } hashtable[nums[i]] = i; } return {}; } };

[complexity analysis]

  • Time complexity: O ( n ) O(n) O(n), n n n is the size of the array
  • Space complexity: O ( n ) O(n) O(n), mainly the cost of hash table

Leetcode 3. Longest substring without duplicate characters

[title]

Given a string s, please find the length of the longest substring that does not contain duplicate characters.

[ideas]

Use the sliding window to obtain the longest substring.
To determine whether there are duplicate characters in the substring, you can use a hash set, such as unordered_set or use an array of tags.

[code 1]

//Time complexity: O(n), the left and right pointers will traverse the array once //Spatial complexity: O(∑), Σ is the size of the character set, which is the overhead used by the hash set to store class Solution { public: int lengthOfLongestSubstring(string s) { //Sliding window: left and right pointers int rk = -1; int len = s.size(); int ans = 0; unordered_set<char> hashTable; for (int i = 0; i < len; i++) { //The left pointer traverses the beginning of the enumeration string if (i != 0) { hashTable.erase(s[i - 1]); //Each time the left pointer moves forward, the previous character is removed from the hash set } while (rk + 1 < len && !hashTable.count(s[rk + 1])) { //Move right pointer hashTable.insert(s[++rk]); } ans = max(ans, rk - i + 1); } return ans; } };

[code 2]

class Solution { public: int lengthOfLongestSubstring(string s) { int vis[130] = ; //Use the tag array, which defaults to all characters with ASCII code within [0128] int left = -1; //Left pointer int ans = 0; for (int i = 0; s[i]; i++) { //Right pointer vis[s[i]]++; while (vis[s[i]] > 1) { left++; vis[s[left]]--; } ans = max(ans, i - left); } return ans; } };

Leetcode 4. Find the median of two positively ordered arrays

For more information, see Leetcode 4. Finding the median of two positively ordered arrays (difficult)

Leetcode 21. Merge two ordered linked lists

/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { ListNode *head = new ListNode(0, nullptr); ListNode *pre = head; while (l1 && l2) { if (l1->val < l2->val) { pre->next = l1; l1 = l1->next; } else { pre->next = l2; l2 = l2->next; } pre = pre->next; } pre->next = l1 ? l1 : l2; return head->next; } };

Leetcode 35. Search for inserted locations

[ideas]

Can be converted to find the first element greater than or equal to the target value

[Code]

class Solution { public: int searchInsert(vector<int>& nums, int target) { //Find the location of the first value greater than or equal to target int low = 0, high = nums.size() - 1, ans = nums.size(); while (low <= high) { int mid = ((high - low) >> 1) + low; if (nums[mid] >= target) { ans = mid; high = mid - 1; } else { low = mid + 1; } } return ans; } };

Leetcode 38. Appearance series

class Solution { public: string ans[35] = {"", "1"}; //Answer array void func(int s1, int s2) { int cnt = 0; //Record the number of character repetitions for (int i = 0; i < ans[s1].size(); i++) { if (cnt == 0 || ans[s1][i - 1] == ans[s1][i]) { cnt++; } else { ans[s2] += cnt + '0'; ans[s2] += ans[s1][i - 1]; cnt = 1; } } ans[s2] += cnt + '0'; ans[s2] += ans[s1][ans[s1].size() - 1]; } string countAndSay(int n) { for (int i = 2; i <= n; i++) { func(i - 1, i); } return ans[n]; } };

Leetcode 88. Merge two ordered arrays

[ideas]

To prevent numbers from being overwritten, compare back to front

[Code]

class Solution { public: void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) { int i = m - 1, j = n - 1; for (int pos = m + n - 1; pos >= 0; pos--) { if (i < 0 || (j >= 0 && nums1[i] < nums2[j])) { nums1[pos] = nums2[j]; j--; } else { nums1[pos] = nums1[i]; i--; } } } };

Leetcode 217. There are duplicate elements

[ideas]

The hash table stores values to determine whether new elements have appeared in the hash table

[Code]

class Solution { public: bool containsDuplicate(vector<int>& nums) { unordered_set<int> hashTable; for (int num : nums) { if (hashTable.count(num)) { return true; } hashTable.insert(num); } return false; } };

Leetcode 219. Repeating Element II

[ideas]

Hashtable

[Code]

class Solution { public: bool containsNearbyDuplicate(vector<int>& nums, int k) { unordered_map<int, int> hashTable; for (int i = 0; i < nums.size(); i++) { if (hashTable.count(nums[i])) { if (abs(hashTable[nums[i]] - i) <= k) return true; } hashTable[nums[i]] = i; } return false; } };

Leetcode 278. First wrong version

[ideas]

This is the special case 2 of binary search. Find the first qualified position

[Code]

// The API isBadVersion is defined for you. // bool isBadVersion(int version); class Solution { public: int firstBadVersion(int n) { //A pile of 0, a pile of 1, find the first 1 int l = 1, r = n; while (l < r) { int mid = l + ((r - l) >> 1); if (isBadVersion(mid)) r = mid; else l = mid + 1; } return l; } };

Leetcode 349. Intersection of two arrays

[ideas]

Two hash tables, one for de duplication

[Code]

class Solution { public: vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { unordered_set<int> h1, h2; //h2 for weight removal vector<int> ans; for (int num : nums1) { h1.insert(num); } for (int num : nums2) { if (h1.count(num) && h2.count(num) == 0) { ans.push_back(num); h2.insert(num); } } return ans; } };

Or as follows:

class Solution { public: vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { unordered_set<int> set1, set2; for (int& num : nums1) set1.insert(num); for (int& num : nums2) set2.insert(num); return getIntersection(set1, set2); } vector<int> getIntersection(unordered_set<int>& set1, unordered_set<int>& set2) { if (set1.size() < set2.size()) return getIntersection(set2, set1); vector<int> ans; for (auto& num : set1) { if (set2.count(num)) ans.push_back(num); } return ans; } };

Leetcode 350. Intersection of two arrays II

[ideas]

Since the same number may appear more than once in both arrays, you need to use a hash table to store the number of occurrences of each number. For a number, the number of occurrences in the intersection is equal to the minimum number of occurrences of the number in two arrays.

First, traverse the first array and record each number in the first array and the corresponding number of occurrences in the hash table, and then traverse the second array. For each number in the second array, if there is this number in the hash table, add the number to the answer and reduce the number of occurrences of this number in the hash table.

In order to reduce the space complexity, first traverse the shorter array and record each number and the corresponding number of occurrences in the hash table, and then traverse the longer array to get the intersection.

[Code]

class Solution { public: vector<int> intersect(vector<int>& nums1, vector<int>& nums2) { if (nums1.size() > nums2.size()) { return intersect(nums2, nums1); } vector<int> ans; unordered_map<int, int> m; //Record the number of occurrences of each number for (int& num : nums1) m[num]++; for (int& num : nums2) { if (m.count(num) && m[num] > 0) { ans.push_back(num); m[num]--; } } return ans; } };

Leetcode 374. Guess the size of the number

[ideas]

Application of binary search

[Code]

/** * Forward declaration of guess API. * @param num your guess * @return -1 if num is lower than the guess number * 1 if num is higher than the guess number * otherwise return 0 * int guess(int num); */ class Solution { public: int guessNumber(int n) { int l = 1, r = n; while (l < r) { int mid = l + ((r - l) >> 1); if (guess(mid) == -1) r = mid - 1; else if (guess(mid) == 1) l = mid + 1; else return mid; } return l; } };

Or write

/** * Forward declaration of guess API. * @param num your guess * @return -1 if num is lower than the guess number * 1 if num is higher than the guess number * otherwise return 0 * int guess(int num); */ class Solution { public: int guessNumber(int n) { int l = 1, r = n; while (l < r) { int mid = l + ((r - l) >> 1); if (guess(mid) <= 0) r = mid; //The result is in [l, mid] else l = mid + 1; } return l; } };

Leetcode 378. The K-th smallest element in an ordered matrix

[ideas]

Application of binary search

[Code]

//Time complexity: O(nlog(r − l)), the number of binary lookups is O(log(r − l)), and the time complexity of each operation is O(n). //Space complexity: O(1). class Solution { public: int getCnt(vector<vector<int>>& matrix, int val) { //The number of not greater than val was found int x = matrix.size() - 1, y = 0, cnt = 0; while(x >= 0 && y < matrix.size()) { if (matrix[x][y] <= val) { cnt += x + 1; y++; } else { x--; } } return cnt; } int kthSmallest(vector<vector<int>>& matrix, int k) { int n = matrix.size(); int left = matrix[0][0], right = matrix[n - 1][n - 1]; while (left < right) { int mid = left + ((right - left) >> 1); if (getCnt(matrix, mid) < k) left = mid + 1; else right = mid; } return left; } };

3 October 2021, 13:50 | Views: 6248

Add new comment

For adding a comment, please log in
or create account

0 comments