├── .gitignore ├── .gitattributes ├── c ├── tools │ ├── swap.h │ ├── compare.h │ ├── queue.h │ ├── stack.c │ ├── stack.h │ └── queue.c ├── algorithms │ ├── sort.h │ ├── sort-insertaion.c │ ├── sort-quick.c │ ├── sort-merge.c │ └── sort-test.c ├── 200-299 │ ├── 292-nim-game.c │ ├── 231-power-of-two.c │ ├── 263-ugly-number.c │ ├── 283-move-zeroes.c │ ├── 268-missing-number.c │ ├── 201-bitwise-and-of-numbers-range.c │ ├── 264-ugly-number-ii.c │ ├── 230-kth-smallest-element-in-a-bst.c │ ├── 202-happy-number.c │ ├── 297-serialize-and-deserialize-binary-tree.c │ ├── 221-maximal-square.c │ ├── 238-product-of-array-except-self.c │ ├── 287-find-the-duplicate-number.c │ ├── 200-number-of-islands.c │ └── 216-combination-sum-iii.c ├── 400-499 │ ├── 461-hamming-distance.c │ ├── 434-number-of-segments-in-a-string.c │ ├── 413-arithmetic-slices.c │ ├── 412-fizz-buzz.c │ ├── 415-add-strings.c │ ├── 486-predict-the-winner.c │ ├── 496-next-greater-element-i.c │ └── 448-find-all-numbers-disappeared-in-an-array.c ├── 300-399 │ ├── 319-bulb-switcher.c │ ├── 357-count-numbers-with-unique-digits.c │ ├── 392-is-subsequence.c │ ├── 367-valid-perfect-square.c │ ├── 371-sum-of-two-integers.c │ ├── 365-water-and-jug-problem.c │ ├── 344-reverse-string.c │ ├── 345-reverse-vowels-of-a-string.c │ ├── 338-counting-bits.c │ ├── 393-utf-8-validation.c │ ├── 377-combination-sum-iv.c │ └── 336-palindrome-pairs.c ├── data-structures │ ├── linked-list.h │ ├── binary-tree.h │ ├── linked-list-test.c │ ├── binary-tree-test.c │ ├── linked-list.c │ ├── array.h │ └── array-test.c ├── 000-099 │ ├── 70-climbing-stairs.c │ ├── 07-reverse-integer.c │ ├── 58-length-of-last-word.c │ ├── 50-powx-n.c │ ├── 27-remove-element.c │ ├── 62-unique-paths.c │ ├── 26-remove-duplicates-from-sorted-array.c │ ├── 55-jump-game.c │ ├── 09-palindrome-number.c │ ├── 28-implement-strstr.c │ ├── 11-container-with-most-water.c │ ├── 35-search-insert-position.c │ ├── 24-swap-nodes-in-pairs.c │ ├── 10-regular-expression-matching.c │ ├── 53-maximum-subarray.c │ ├── 42-trapping-rain-water.c │ ├── 75-sort-colors.c │ ├── 08-string-to-integer-atoi.c │ ├── 98-validate-binary-search-tree.c │ ├── 21-merge-two-sorted-lists.c │ ├── 14-longest-common-prefix.c │ ├── 64-minimum-path-sum.c │ ├── 83-remove-duplicates-from-sorted-list.c │ ├── 48-rotate-image.c │ ├── 01-two-sum.c │ ├── 41-first-missing-positive.c │ ├── 63-unique-paths-ii.c │ ├── 13-roman-to-integer.c │ ├── 61-rotate-list.c │ ├── 74-search-a-2d-matrix.c │ ├── 73-set-matrix-zeroes.c │ ├── 66-plus-one.c │ ├── 43-multiply-strings.c │ ├── 05-longest-palindromic-substring.c │ ├── 12-integer-to-roman.c │ ├── 22-generate-parentheses.c │ ├── 34-search-for-a-range.c │ ├── 93-restore-ip-addresses.c │ ├── 59-spiral-matrix-ii.c │ ├── 20-valid-parentheses.c │ ├── 79-word-search.c │ ├── 46-permutations.c │ ├── 78-subsets.c │ ├── 33-search-in-rotated-sorted-array.c │ ├── 54-spiral-matrix.c │ ├── 94-binary-tree-inorder-traversal.c │ ├── 32-longest-valid-parentheses.c │ ├── 45-jump-game-ii.c │ ├── 02-add-two-numbers.c │ ├── 03-longest-substring-without-repeating-characters.c │ ├── 15-3sum.c │ ├── 19-remove-nth-node-from-end-of-list.c │ └── 39-combination-sum.c ├── 100-199 │ ├── 136-single-number.c │ ├── 190-reverse-bits.c │ ├── 122-best-time-to-buy-and-sell-stock-ii.c │ ├── 112-path-sum.c │ ├── 191-number-of-1-bits.c │ ├── 165-compare-version-numbers.c │ ├── 141-linked-list-cycle.c │ ├── 108-convert-sorted-array-to-binary-search-tree.c │ ├── 109-convert-sorted-list-to-binary-search-tree.c │ ├── 150-evaluate-reverse-polish-notation.c │ ├── 102-binary-tree-level-order-traversal.c │ ├── 105-construct-binary-tree-from-preorder-and-inorder-traversal.c │ └── 113-path-sum-ii.c ├── 600-699 │ ├── 693-binary-number-with-alternating-bits.c │ ├── 605-can-place-flowers.c │ └── 678-valid-parenthesis-string.c ├── 800-899 │ ├── 876-middle-of-the-linked-list.c │ ├── 868-binary-gap.c │ ├── 844-backspace-string-compare.c │ ├── 838-push-dominoes.c │ └── 885-spiral-matrix-iii.c ├── 500-599 │ ├── 551-student-attendance-record-i.c │ ├── 560-subarray-sum-equals-k.c │ ├── 540-single-element-in-a-sorted-array.c │ ├── 557-reverse-words-in-a-string-iii.c │ ├── 541-reverse-string-ii.c │ ├── 543-diameter-of-binary-tree.c │ ├── 530-minimum-absolute-difference-in-bst.c │ ├── 525-contiguous-array.c │ └── 539-minimum-time-difference.c ├── 700-799 │ ├── 717-1-bit-and-2-bit-characters.c │ ├── 779-k-th-symbol-in-grammar.c │ ├── 704-binary-search.c │ └── 741-network-delay-time.c ├── 1200-1299 │ ├── 1290-convert-binary-number-in-a-linked-list-to-integer.c │ └── 1220-count-vowels-permutation.c ├── 900-999 │ ├── 925-long-pressed-name.c │ ├── 990-satisfiability-of-equality-equations.c │ └── 985-sum-of-even-numbers-after-queries.c ├── 1600-1699 │ └── 1680-concatenation-of-consecutive-binary-numbers.c ├── 1100-1199 │ ├── 1108-defanging-an-ip-address.c │ ├── 1103-distribute-candies-to-people.c │ └── 1138-alphabet-board-path.c ├── 1000-1099 │ ├── 1046-last-stone-weight.c │ ├── 1051-height-checker.c │ └── 1008-construct-binary-search-tree-from-preorder-traversal.c ├── 000 │ ├── counting-elements.c │ ├── perform-string-shifts.c │ └── leftmost-column-with-at-least-a-one.c ├── 2300-2399 │ └── 2352-equal-row-and-column-pairs.c ├── 1400-1499 │ └── 1410-html-entity-parser.c ├── 1700-1799 │ └── 1770-maximum-score-from-performing-multiplication-operations_MLE_TLE.c └── test.sh ├── README.md ├── Shell.sh └── Database.sql /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.h linguist-language=c 2 | -------------------------------------------------------------------------------- /c/tools/swap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #ifndef C_TOOLS_SWAP_H_ 7 | #define C_TOOLS_COMPARE_H_ 8 | 9 | void swap_ints(int *a, int *b) { 10 | int tmp = *a; 11 | *a = *b; 12 | *b = tmp; 13 | } 14 | 15 | #endif /* C_TOOLS_SWAP_H_ */ 16 | -------------------------------------------------------------------------------- /c/algorithms/sort.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #ifndef C_ALGORITHMS_SORT_H_ 7 | #define C_ALGORITHMS_SORT_H_ 8 | 9 | /* 插入排序 */ 10 | void sortInsertion(int *a, int len); 11 | 12 | /* 归并排序 */ 13 | void sortMerge(int *a, int len); 14 | 15 | /* 快速排序 */ 16 | void sortQuick(int *a, int len); 17 | 18 | #endif /* C_ALGORITHMS_SORT_H_ */ 19 | -------------------------------------------------------------------------------- /c/algorithms/sort-insertaion.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/algorithms/sort.h" 7 | 8 | void sortInsertion(int *a, int len) { 9 | int i, j, key; 10 | for (j = 1; j < len; ++j) { 11 | key = a[j]; 12 | i = j - 1; 13 | while (i >= 0 && a[i] > key) { 14 | a[i+1] = a[i]; 15 | --i; 16 | } 17 | a[i+1] = key; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /c/200-299/292-nim-game.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 从1开始模拟你的行为, 你会发现代码出乎意料的简单. 6 | */ 7 | 8 | #include 9 | #include "c/test.h" 10 | 11 | bool canWinNim(int n) { 12 | return n % 4 > 0; 13 | } 14 | 15 | void test(bool expect, int n) { 16 | EXPECT_EQ_INT(expect, canWinNim(n)); 17 | } 18 | 19 | int main(void) { 20 | test(false, 4); 21 | 22 | return testOutput(); 23 | } 24 | -------------------------------------------------------------------------------- /c/400-499/461-hamming-distance.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 异或后计算1的个数 6 | */ 7 | 8 | #include "c/test.h" 9 | 10 | int hammingDistance(int x, int y) { 11 | int count = 0; 12 | for (x ^= y; x; x >>= 1) { 13 | count += x & 1; 14 | } 15 | return count; 16 | } 17 | 18 | void test(int expect, int x, int y) { 19 | EXPECT_EQ_INT(expect, hammingDistance(x, y)); 20 | } 21 | 22 | int main(void) { 23 | test(2, 1, 4); 24 | 25 | return testOutput(); 26 | } 27 | -------------------------------------------------------------------------------- /c/200-299/231-power-of-two.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 是2的几次方数的特点是首位是'1', 其他全是'0', 所以用 x & x-1 的技巧就能判断出 6 | */ 7 | 8 | #include 9 | #include "c/test.h" 10 | 11 | bool isPowerOfTwo(int n) { 12 | return n > 0 && !(n & (n - 1)); 13 | } 14 | 15 | void test(bool expect, int n) { 16 | EXPECT_EQ_INT(expect, isPowerOfTwo(n)); 17 | } 18 | 19 | int main(void) { 20 | test(true, 1); 21 | test(true, 16); 22 | test(false, 218); 23 | 24 | return testOutput(); 25 | } 26 | -------------------------------------------------------------------------------- /c/tools/compare.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2020, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #ifndef C_TOOLS_COMPARE_H_ 7 | #define C_TOOLS_COMPARE_H_ 8 | 9 | int compare_ints(const void *a, const void *b) { 10 | int arg1 = *(const int *)a; 11 | int arg2 = *(const int *)b; 12 | if (arg1 < arg2) return -1; 13 | if (arg1 > arg2) return 1; 14 | return 0; 15 | } 16 | 17 | int compare_ints_desc(const void *a, const void *b) { 18 | return compare_ints(a, b) * -1; 19 | } 20 | 21 | #endif /* C_TOOLS_COMPARE_H_ */ 22 | -------------------------------------------------------------------------------- /c/300-399/319-bulb-switcher.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 感觉是个数学问题,但还是先用了朴素方法解,结果超时 6 | * 后来找了下规律,发现结果是 sqrt(n) 7 | */ 8 | 9 | #include /* sqrt() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | int bulbSwitch(int n) { 14 | return (int)sqrt(n); 15 | } 16 | 17 | void test(int expect, int n) { 18 | EXPECT_EQ_INT(expect, bulbSwitch(n)); 19 | } 20 | 21 | int main(void) { 22 | test(1, 3); 23 | test(316, 99999); 24 | 25 | return testOutput(); 26 | } 27 | -------------------------------------------------------------------------------- /c/data-structures/linked-list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2018, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #ifndef C_DATA_STRUCTURES_LINKED_LIST_H_ 7 | #define C_DATA_STRUCTURES_LINKED_LIST_H_ 8 | 9 | struct ListNode { 10 | int val; 11 | struct ListNode *next; 12 | }; 13 | 14 | struct ListNode *linkedlistParse(const char *str); 15 | char *linkedlistToString(struct ListNode *list); 16 | void linkedlistFree(struct ListNode *list); 17 | 18 | int linkedlistLength(struct ListNode *list); 19 | 20 | #endif /* C_DATA_STRUCTURES_LINKED_LIST_H_ */ 21 | -------------------------------------------------------------------------------- /c/000-099/70-climbing-stairs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 实际答案就是斐波那契数列 6 | * 一开始用递归解, 但超时了 7 | * 后改为非递归 8 | */ 9 | 10 | #include "c/test.h" 11 | 12 | int climbStairs(int n) { 13 | int a = 1, b = 1; 14 | for (int i = 1; i < n; i++) { 15 | a = a + b; 16 | b = a - b; 17 | } 18 | return a; 19 | } 20 | 21 | void test(int expect, int n) { 22 | EXPECT_EQ_INT(expect, climbStairs(n)); 23 | } 24 | 25 | int main(void) { 26 | test(1, 1); 27 | test(2, 2); 28 | test(89, 10); 29 | 30 | return testOutput(); 31 | } 32 | -------------------------------------------------------------------------------- /c/tools/queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #ifndef C_TOOLS_QUEUE_H_ 7 | #define C_TOOLS_QUEUE_H_ 8 | 9 | #include 10 | 11 | #ifndef QUEUE_INIT_SIZE 12 | #define QUEUE_INIT_SIZE 64 13 | #endif 14 | 15 | struct Queue { 16 | int front, rear, size; 17 | void **array; 18 | }; 19 | 20 | struct Queue *queueMake(); 21 | void queueFree(struct Queue *q); 22 | 23 | bool queueIsEmpty(struct Queue *q); 24 | void queueOffer(struct Queue *q, void *e); 25 | void *queuePoll(struct Queue *q); 26 | 27 | #endif /* C_TOOLS_QUEUE_H_ */ 28 | -------------------------------------------------------------------------------- /c/300-399/357-count-numbers-with-unique-digits.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 排列组合的知识点 6 | */ 7 | 8 | #include "c/test.h" 9 | 10 | int countNumbersWithUniqueDigits(int n) { 11 | int count = 1; 12 | int v = 1; 13 | for (int i = 1; i <= n; i++) { 14 | v *= 11 - i - (i == 1 ? 1 : 0); 15 | count += v; 16 | } 17 | return count; 18 | } 19 | 20 | void test(int expect, int n) { 21 | EXPECT_EQ_INT(expect, countNumbersWithUniqueDigits(n)); 22 | } 23 | 24 | int main(void) { 25 | test(91, 2); 26 | 27 | return testOutput(); 28 | } 29 | -------------------------------------------------------------------------------- /c/200-299/263-ugly-number.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 注意需要单独判断 num=0 的情况. 6 | */ 7 | 8 | #include 9 | #include "c/test.h" 10 | 11 | bool isUgly(int num) { 12 | if (num == 0) return false; 13 | while (num % 2 == 0) num /= 2; 14 | while (num % 3 == 0) num /= 3; 15 | while (num % 5 == 0) num /= 5; 16 | 17 | return num == 1; 18 | } 19 | 20 | 21 | void test(bool expect, int num) { 22 | EXPECT_EQ_INT(expect, isUgly(num)); 23 | } 24 | 25 | int main(void) { 26 | test(true, 6); 27 | test(true, 8); 28 | test(false, 14); 29 | 30 | return testOutput(); 31 | } 32 | -------------------------------------------------------------------------------- /c/data-structures/binary-tree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #ifndef C_DATA_STRUCTURES_BINARY_TREE_H_ 7 | #define C_DATA_STRUCTURES_BINARY_TREE_H_ 8 | 9 | struct TreeNode { 10 | int val; 11 | struct TreeNode *left; 12 | struct TreeNode *right; 13 | }; 14 | 15 | struct TreeNode *treeNewNode(int val); 16 | struct TreeNode *treeParse(const char *str); 17 | char *treeToString(struct TreeNode *tree); 18 | void treeFree(struct TreeNode *tree); 19 | 20 | int treeHeight(struct TreeNode *tree); 21 | int treeCount(struct TreeNode *tree); 22 | 23 | #endif /* C_DATA_STRUCTURES_BINARY_TREE_H_ */ 24 | -------------------------------------------------------------------------------- /c/000-099/07-reverse-integer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 需要考虑 int 的边界. 6 | */ 7 | 8 | #include "c/test.h" 9 | 10 | int reverse(int x) { 11 | int rt = 0, tmp; 12 | while (x) { 13 | tmp = rt * 10 + x % 10; 14 | if ((tmp / 10) != rt) return 0; 15 | rt = tmp; 16 | x /= 10; 17 | } 18 | return rt; 19 | } 20 | 21 | void test(int expect, int x) { 22 | EXPECT_EQ_INT(expect, reverse(x)); 23 | } 24 | 25 | /* 26 | Example1: x = 123, return 321 27 | Example2: x = -123, return -321 28 | */ 29 | int main(void) { 30 | test(321, 123); 31 | test(-321, -123); 32 | 33 | return testOutput(); 34 | } 35 | -------------------------------------------------------------------------------- /c/300-399/392-is-subsequence.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 双指针往前跑即可 6 | * PS: Copilot 真的猛, 在函数内直接补全了, 试试看的态度提交到 leetcode 上, 竟然 AC 了, 当然最后把代码删掉重写的. 7 | */ 8 | 9 | #include 10 | #include "c/test.h" 11 | 12 | bool isSubsequence(char *s, char *t) { 13 | while (*s != '\0' && *t != '\0') { 14 | if (*s == *t) s++; 15 | t++; 16 | } 17 | return *s == '\0'; 18 | } 19 | 20 | void test(bool expect, char *s, char *t) { 21 | EXPECT_EQ_INT(expect, isSubsequence(s, t)); 22 | } 23 | 24 | int main(void) { 25 | test(true, "abc", "ahbgdc"); 26 | test(false, "axc", "ahbgdc"); 27 | 28 | return testOutput(); 29 | } 30 | -------------------------------------------------------------------------------- /c/000-099/58-length-of-last-word.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 很简单的问题, 但第一次提交时, 没有考虑结尾有空格的情况. 6 | */ 7 | 8 | #include "c/test.h" 9 | 10 | int lengthOfLastWord(char *s) { 11 | int length = 0; 12 | char *p = s; 13 | while (*p) { 14 | if (*p++ == ' ') { 15 | while (*p == ' ') p++; 16 | if (*p) length = 0; 17 | } else { 18 | length++; 19 | } 20 | } 21 | return length; 22 | } 23 | 24 | 25 | void test(int expect, char *s) { 26 | EXPECT_EQ_INT(expect, lengthOfLastWord(s)); 27 | } 28 | 29 | int main(void) { 30 | test(5, "Hello World"); 31 | 32 | test(1, "a "); 33 | 34 | return testOutput(); 35 | } 36 | -------------------------------------------------------------------------------- /c/100-199/136-single-number.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 利用或运算 (a ^ a = 0) 6 | */ 7 | 8 | #include "c/data-structures/array.h" 9 | #include "c/test.h" 10 | 11 | int singleNumber(int *nums, int numsSize) { 12 | int rtn = 0; 13 | for (int i = 0; i < numsSize; i++) 14 | rtn ^= nums[i]; 15 | return rtn; 16 | } 17 | 18 | void test(int expect, const char *str) { 19 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 20 | 21 | EXPECT_EQ_INT(expect, singleNumber(arrayValue(e), arraySize(e))); 22 | 23 | arrayFree(e); 24 | } 25 | 26 | int main(void) { 27 | test(100, "[300, 200, 100, 200, 300]"); 28 | 29 | return testOutput(); 30 | } 31 | -------------------------------------------------------------------------------- /c/data-structures/linked-list-test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2018, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/data-structures/linked-list.h" 7 | #include "c/test.h" 8 | 9 | void testLinkedListRoundTrip(const char *str, int expectLength) { 10 | struct ListNode *list = linkedlistParse(str); 11 | 12 | EXPECT_EQ_INT(expectLength, linkedlistLength(list)); 13 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(str, linkedlistToString(list)); 14 | 15 | linkedlistFree(list); 16 | } 17 | 18 | int main(void) { 19 | testLinkedListRoundTrip("[]", 0); 20 | testLinkedListRoundTrip("[0]", 1); 21 | testLinkedListRoundTrip("[-2147483648,0,2147483647]", 3); 22 | 23 | return testOutput(); 24 | } 25 | -------------------------------------------------------------------------------- /c/data-structures/binary-tree-test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/data-structures/binary-tree.h" 7 | #include "c/test.h" 8 | 9 | void testBinaryTreeRoundTrip(const char *str, int height) { 10 | struct TreeNode *tree = treeParse(str); 11 | 12 | EXPECT_EQ_INT(height, treeHeight(tree)); 13 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(str, treeToString(tree)); 14 | 15 | treeFree(tree); 16 | } 17 | 18 | int main(void) { 19 | testBinaryTreeRoundTrip("[]", 0); 20 | testBinaryTreeRoundTrip("[1,2,3]", 2); 21 | testBinaryTreeRoundTrip("[1,null,2,3]", 3); 22 | testBinaryTreeRoundTrip("[5,4,7,3,null,2,null,-1,null,9]", 4); 23 | 24 | return testOutput(); 25 | } 26 | -------------------------------------------------------------------------------- /c/300-399/367-valid-perfect-square.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 牛顿法: 循环调用 x = (x + S/x) / 2 6 | */ 7 | 8 | #include 9 | #include /* int64_t */ 10 | #include "c/test.h" 11 | 12 | bool isPerfectSquare(int num) { 13 | int64_t x = num; /* x为int时, 会溢出 */ 14 | while (x * x > num) 15 | x = (x + num/x) / 2; 16 | return x * x == num; 17 | } 18 | 19 | void test(bool expect, int num) { 20 | EXPECT_EQ_INT(expect, isPerfectSquare(num)); 21 | } 22 | 23 | /* 24 | Input: 16 25 | Returns: True 26 | 27 | Input: 14 28 | Returns: False 29 | */ 30 | int main(void) { 31 | test(true, 16); 32 | test(false, 14); 33 | 34 | return testOutput(); 35 | } 36 | -------------------------------------------------------------------------------- /c/600-699/693-binary-number-with-alternating-bits.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 如果是'0','1'间隔的数, 在右移1位后, 再与原来的数进行异或(XOR)运算, 得到的将是一个全是'1'的数 6 | * 检测全是1的数就很容易了, 直接 (x & x+1) == 0 7 | */ 8 | 9 | #include 10 | #include 11 | #include "c/test.h" 12 | 13 | bool hasAlternatingBits(int n) { 14 | n ^= n >> 1; 15 | return n == INT_MAX || !(n & (n + 1)); 16 | } 17 | 18 | void test(bool expect, int n) { 19 | EXPECT_EQ_INT(expect, hasAlternatingBits(n)); 20 | } 21 | 22 | int main(void) { 23 | test(true, 5); 24 | test(false, 7); 25 | test(false, 11); 26 | test(true, 10); 27 | 28 | test(true, 1431655765); /* Leecode 会有 溢出的检测 */ 29 | 30 | return testOutput(); 31 | } 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [LeetCode OJ](https://leetcode.com/) 2 | 3 | - 定期刷题, 为了保持思维的活跃 4 | - 只用 C 解题, 手写数据结构和对内存的管理 5 | - 每个 solution 都包含单元测试 6 | - 最后, 特别感谢 [miloyip/json-tutorial](https://github.com/miloyip/json-tutorial) 7 | 8 | ## 脚本使用说明 9 | 10 | ``` sh 11 | # 执行第1题 12 | c/test.sh 1 13 | # 执行前10题 14 | c/test.sh $(seq 10) 15 | # 执行全部题 16 | c/test.sh all 17 | # 执行库文件的测试 18 | c/test.sh lib 19 | 20 | # -m 开启内存泄露检查, 使用valgrind, 如 21 | c/test.sh -m 1 22 | c/test.sh -m all 23 | c/test.sh -m lib 24 | ``` 25 | 注意, 有一些没有编号的题放在 `c/000/` 目录下 26 | ```sh 27 | # 用法: c/test.sh <文件名前缀> 28 | # 原理: ls "c/000/$1*.c" 29 | # 例如: c/000/perform-string-shifts.c 30 | c/test.sh perform-string-shift 31 | # 或 32 | c/test.sh perform 33 | ``` 34 | 35 | ## 其他 36 | 37 | 官方会调整函数的参数以及测试用例 38 | 如果有小伙伴发现失效的解答 39 | 可以提醒我一下, 多谢~❤️ 40 | -------------------------------------------------------------------------------- /c/000-099/50-powx-n.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 第一次的时候没有考虑 n 为负数的情况 6 | * 测试数据里有 n == INT_MIN, 所以当 n < 0 时, 需要转换了一下. 7 | */ 8 | 9 | #include /* INT_MIN, INT_MAX */ 10 | #include /* pow() */ 11 | #include "c/test.h" 12 | 13 | double myPow(double x, int n) { 14 | if (n == 0) return 1; 15 | if (n < 0) return 1 / myPow(x, -(n+1)) / x; 16 | 17 | double tmp = myPow(x, n/2); 18 | return (n % 2 == 0 ? 1 : x) * tmp * tmp; 19 | } 20 | 21 | void test(double x, int n) { 22 | EXPECT_EQ_DOUBLE(pow(x, n), myPow(x, n)); 23 | } 24 | 25 | int main(void) { 26 | test(3.0, 2); 27 | test(-3.0, 2); 28 | test(INT_MIN, 3); 29 | test(INT_MAX, 3); 30 | 31 | return testOutput(); 32 | } 33 | -------------------------------------------------------------------------------- /c/800-899/876-middle-of-the-linked-list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/data-structures/linked-list.h" 7 | #include "c/test.h" 8 | 9 | struct ListNode *middleNode(struct ListNode *head) { 10 | struct ListNode *p1 = head, *p2 = head; 11 | 12 | while (p2 != NULL && p2->next != NULL) { 13 | p1 = p1->next; 14 | p2 = p2->next->next; 15 | } 16 | return p1; 17 | } 18 | 19 | void test(int expect, char *s) { 20 | struct ListNode *head = linkedlistParse(s); 21 | 22 | EXPECT_EQ_INT(expect, middleNode(head)->val); 23 | 24 | linkedlistFree(head); 25 | } 26 | 27 | int main(void) { 28 | test(3, "[1,2,3,4,5]"); 29 | test(4, "[1,2,3,4,5,6]"); 30 | 31 | return testOutput(); 32 | } 33 | -------------------------------------------------------------------------------- /c/000-099/27-remove-element.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/data-structures/array.h" 7 | #include "c/test.h" 8 | 9 | int removeElement(int *nums, int numsSize, int val) { 10 | int i = 0, j = 0; 11 | for (; j < numsSize; j++) 12 | if (nums[j] != val) nums[i++] = nums[j]; 13 | return i; 14 | } 15 | 16 | void test(const char* expect, const char* str, int val) { 17 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 18 | arraySetSize(e, removeElement(arrayValue(e), arraySize(e), val)); 19 | 20 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString(e)); 21 | 22 | arrayFree(e); 23 | } 24 | 25 | int main(void) { 26 | test("[2,2]", "[3,2,2,3]", 3); 27 | 28 | return testOutput(); 29 | } 30 | -------------------------------------------------------------------------------- /c/algorithms/sort-quick.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/algorithms/sort.h" 7 | 8 | static void exchange(int *a, int *b) { 9 | int tmp = *a; 10 | *a = *b; 11 | *b = tmp; 12 | } 13 | 14 | static int partition(int *a, int p, int r) { 15 | int i, j, x = a[r]; 16 | for (i = p - 1, j = p; j < r; ++j) { 17 | if (a[j] <= x) { 18 | i++; 19 | exchange(&a[i], &a[j]); 20 | } 21 | } 22 | exchange(&a[i+1], &a[r]); 23 | return i+1; 24 | } 25 | 26 | static void sort(int *a, int p, int r) { 27 | if (p >= r) return; 28 | int q = partition(a, p, r); 29 | sort(a, p, q-1); 30 | sort(a, q+1, r); 31 | } 32 | 33 | void sortQuick(int *a, int len) { 34 | sort(a, 0, len - 1); 35 | } 36 | -------------------------------------------------------------------------------- /c/500-599/551-student-attendance-record-i.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 第一次提交的时候才发现又审错题了, Late 是连续3次, 而不是总共3次. 6 | */ 7 | 8 | #include 9 | #include "c/test.h" 10 | 11 | bool checkRecord(char *s) { 12 | int a = 0, l = 0; 13 | while (*s != '\0') { 14 | if (*s == 'L') { 15 | if (++l > 2) return false; 16 | } else { 17 | l = 0; 18 | } 19 | 20 | if (*s == 'A') { 21 | if (++a > 1) return false; 22 | } 23 | 24 | s++; 25 | } 26 | return true; 27 | } 28 | 29 | void test(bool expect, char *s) { 30 | EXPECT_EQ_INT(expect, checkRecord(s)); 31 | } 32 | 33 | int main(void) { 34 | test(true, "PPALLP"); 35 | test(false, "PPALLL"); 36 | 37 | return testOutput(); 38 | } 39 | -------------------------------------------------------------------------------- /c/700-799/717-1-bit-and-2-bit-characters.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 从头开始遍历, 遇到1前进两步, 遇到0前进一步. 6 | */ 7 | 8 | #include 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | bool isOneBitCharacter(int *bits, int bitsSize) { 13 | int i = 0; 14 | while (i < bitsSize - 1) { 15 | i += bits[i] ? 2 : 1; 16 | } 17 | return i != bitsSize; 18 | } 19 | 20 | void test(bool expect, char *s) { 21 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 22 | 23 | EXPECT_EQ_INT(expect, isOneBitCharacter(arrayValue(e), arraySize(e))); 24 | 25 | arrayFree(e); 26 | } 27 | 28 | int main(void) { 29 | test(true, "[1, 0, 0]"); 30 | test(false, "[1, 1, 1, 0]"); 31 | 32 | return testOutput(); 33 | } 34 | -------------------------------------------------------------------------------- /c/000-099/62-unique-paths.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 最简单的 DP 问题, 设置好边界, 其他每个点 = 左边 + 上边 6 | */ 7 | 8 | #include "c/test.h" 9 | 10 | int uniquePaths(int m, int n) { 11 | // m n 12 | int grid[100][100]; /* 题目已说上限, 就不动态创建了 */ 13 | grid[0][0] = 1; 14 | 15 | int i, j; 16 | for (i = 1; i < m; i++) grid[i][0] = 1; 17 | for (i = 1; i < n; i++) grid[0][i] = 1; 18 | 19 | for (i = 1; i < m; i++) 20 | for (j = 1; j < n; j++) 21 | grid[i][j] = grid[i-1][j] + grid[i][j-1]; 22 | 23 | return grid[m-1][n-1]; 24 | } 25 | 26 | void test(int expect, int m, int n) { 27 | EXPECT_EQ_INT(expect, uniquePaths(m, n)); 28 | } 29 | 30 | int main(void) { 31 | test(28, 3, 7); 32 | 33 | return testOutput(); 34 | } 35 | -------------------------------------------------------------------------------- /c/800-899/868-binary-gap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 位运算, 可以省空间, 记录下标, 计算最大距离即可 6 | */ 7 | 8 | #include 9 | #include "c/test.h" 10 | 11 | int binaryGap(int N) { 12 | int rt = 0, k = 0, index; 13 | bool find = false; 14 | while (N) { 15 | k++; 16 | if (N & 1) { 17 | if (find) { 18 | if (k - index > rt) rt = k - index; 19 | } else { 20 | find = true; 21 | } 22 | index = k; 23 | } 24 | N >>= 1; 25 | } 26 | 27 | return rt; 28 | } 29 | 30 | void test(int expect, int N) { 31 | EXPECT_EQ_INT(expect, binaryGap(N)); 32 | } 33 | 34 | int main(void) { 35 | test(2, 22); 36 | test(2, 5); 37 | test(1, 6); 38 | test(0, 8); 39 | 40 | return testOutput(); 41 | } 42 | -------------------------------------------------------------------------------- /c/100-199/190-reverse-bits.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include /* uint32_t */ 7 | #include "c/test.h" 8 | 9 | uint32_t reverseBits(uint32_t n) { 10 | uint32_t rt = 0; 11 | for (int i = 0; i < (int)sizeof(uint32_t) * 8; ++i) { 12 | rt = (rt << 1) + (n & 1); 13 | n = n >> 1; 14 | } 15 | return rt; 16 | } 17 | 18 | void test(uint32_t expect, uint32_t n) { 19 | EXPECT_EQ_INT(expect, reverseBits(n)); 20 | } 21 | 22 | /* 23 | For example, 24 | given input 43261596 (represented in binary as 00000010100101000001111010011100), 25 | return 964176192 (represented in binary as 00111001011110000010100101000000). 26 | */ 27 | int main(void) { 28 | test(964176192, 43261596); 29 | 30 | return testOutput(); 31 | } 32 | -------------------------------------------------------------------------------- /c/700-799/779-k-th-symbol-in-grammar.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 递归解法, 转换成 0-indexed 会更好理解, N 是个无用的参数 6 | * 0 1 7 | * | \ | \ 8 | * 0 1 1 0 9 | * = ^ = ^ 10 | */ 11 | 12 | #include "c/test.h" 13 | 14 | int cal(int k) { 15 | if (k == 0) return 0; 16 | 17 | if (k % 2 == 1) 18 | return 1 ^ cal(k/2); 19 | else 20 | return cal(k/2); 21 | } 22 | 23 | int kthGrammar(int N, int K) { 24 | // 将 K 从 1-indexed 转化成 0-indexed 25 | return cal(--K); 26 | } 27 | 28 | void test(int expect, int N, int K) { 29 | EXPECT_EQ_INT(expect, kthGrammar(N, K)); 30 | } 31 | 32 | int main(void) { 33 | test(0, 1, 1); 34 | test(0, 2, 1); 35 | test(1, 2, 2); 36 | test(1, 4, 5); 37 | 38 | return testOutput(); 39 | } 40 | -------------------------------------------------------------------------------- /c/300-399/371-sum-of-two-integers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 模拟 5 + 3 的计算: 6 | * 1 0 1 7 | * 1 1 8 | * - - - - - - - 9 | * 1 1 0 -> a 10 | * 1 0 -> b 11 | * - - - - - - - 12 | * 1 0 0 13 | * 1 0 0 14 | * - - - - - - - 15 | * 0 16 | * 1 0 0 0 17 | * - - - - - - - 18 | * 1 0 0 0 19 | * 0 20 | * - - - - - - - 21 | * 1 0 0 0 22 | */ 23 | 24 | #include "c/test.h" 25 | 26 | int getSum(int a, int b) { 27 | int tmp; 28 | while (b) { 29 | tmp = a; 30 | a = tmp ^ b; 31 | b = (tmp & b) << 1; 32 | } 33 | return a; 34 | } 35 | 36 | void test(int a, int b) { 37 | EXPECT_EQ_INT(a+b, getSum(a, b)); 38 | } 39 | 40 | int main(void) { 41 | test(3, 5); 42 | 43 | return testOutput(); 44 | } 45 | -------------------------------------------------------------------------------- /c/400-499/434-number-of-segments-in-a-string.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 注意, 计数时需要判断多个空格的情况 6 | */ 7 | 8 | #include 9 | #include "c/test.h" 10 | 11 | int countSegments(char *s) { 12 | int rt = 0; 13 | bool space = true; 14 | 15 | while (*s != '\0') { 16 | if (space) { 17 | while (*s == ' ') { s++; } 18 | space = false; 19 | } else { 20 | while (*s != ' ' && *s != '\0') { s++; } 21 | space = true; 22 | rt++; 23 | } 24 | } 25 | return rt; 26 | } 27 | 28 | void test(int expect, char *s) { 29 | EXPECT_EQ_INT(expect, countSegments(s)); 30 | } 31 | 32 | int main(void) { 33 | test(5, "Hello, my name is John "); 34 | test(0, ""); 35 | test(0, " "); 36 | 37 | return testOutput(); 38 | } 39 | -------------------------------------------------------------------------------- /c/1200-1299/1290-convert-binary-number-in-a-linked-list-to-integer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/data-structures/linked-list.h" 7 | #include "c/test.h" 8 | 9 | int getDecimalValue(struct ListNode *head) { 10 | int rtn = 0; 11 | while (head != NULL) { 12 | rtn <<= 1; 13 | rtn += head->val; 14 | head = head->next; 15 | } 16 | return rtn; 17 | } 18 | 19 | void test(int expect, const char *s) { 20 | struct ListNode *head = linkedlistParse(s); 21 | EXPECT_EQ_INT(expect, getDecimalValue(head)); 22 | linkedlistFree(head); 23 | } 24 | 25 | int main(void) { 26 | test(5, "[1,0,1]"); 27 | test(0, "[0]"); 28 | test(1, "[1]"); 29 | test(18880, "[1,0,0,1,0,0,1,1,1,0,0,0,0,0,0]"); 30 | test(0, "[0,0]"); 31 | 32 | return testOutput(); 33 | } 34 | -------------------------------------------------------------------------------- /c/000-099/26-remove-duplicates-from-sorted-array.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | #include "c/data-structures/array.h" 8 | #include "c/test.h" 9 | 10 | int removeDuplicates(int *nums, int numsSize) { 11 | if (numsSize == 0) return 0; 12 | int i = 0, j = 1; 13 | for (; j < numsSize; j++) 14 | if (nums[j] != nums[i]) nums[++i] = nums[j]; 15 | return i + 1; 16 | } 17 | 18 | void test(const char *expect, const char *str) { 19 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 20 | arraySetSize(e, removeDuplicates(arrayValue(e), arraySize(e))); 21 | 22 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString(e)); 23 | 24 | arrayFree(e); 25 | } 26 | 27 | int main(void) { 28 | test("[1,2]", "[1,1,2]"); 29 | 30 | return testOutput(); 31 | } 32 | -------------------------------------------------------------------------------- /c/100-199/122-best-time-to-buy-and-sell-stock-ii.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 直觉就是所有相邻两个数的差为正数时的累加. 6 | * 提交竟然过了. 7 | */ 8 | 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | int maxProfit(int *prices, int pricesSize) { 13 | int max = 0; 14 | for (int i = 1; i < pricesSize; i++) { 15 | if (prices[i] > prices[i - 1]) { 16 | max += prices[i] - prices[i - 1]; 17 | } 18 | } 19 | return max; 20 | } 21 | 22 | void test(int expect, char *s) { 23 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 24 | EXPECT_EQ_INT(expect, maxProfit(arrayValue(e), arraySize(e))); 25 | arrayFree(e); 26 | } 27 | 28 | int main(void) { 29 | test(7, "[7,1,5,3,6,4]"); 30 | test(4, "[1,2,3,4,5]"); 31 | test(0, "[7,6,4,3,1]"); 32 | 33 | return testOutput(); 34 | } 35 | -------------------------------------------------------------------------------- /c/300-399/365-water-and-jug-problem.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | 5 | * z 不能大于 MAX(x, y), 因为 z 一定要装在一个壶里. 6 | * 求出x和y的最大公约数, 然后看能不能被z整除, 就是该问题的解. 7 | */ 8 | 9 | #include 10 | #include "c/test.h" 11 | 12 | int gcd(int a, int b) { 13 | if (b == 0) return a; 14 | return gcd(b, a%b); 15 | } 16 | 17 | bool canMeasureWater(int x, int y, int z) { 18 | if (z > x && z > y) return false; 19 | return z % gcd(x, y) == 0; 20 | } 21 | 22 | void test(bool expect, int x, int y, int z) { 23 | EXPECT_EQ_INT(expect, canMeasureWater(x, y, z)); 24 | } 25 | 26 | /* 27 | Input: x = 3, y = 5, z = 4 28 | Output: True 29 | 30 | Input: x = 2, y = 6, z = 5 31 | Output: False 32 | */ 33 | int main(void) { 34 | test(true, 3, 5, 4); 35 | test(false, 2, 6, 5); 36 | 37 | return testOutput(); 38 | } 39 | -------------------------------------------------------------------------------- /c/900-999/925-long-pressed-name.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 两个指针向后移动即可 6 | */ 7 | 8 | #include 9 | #include "c/test.h" 10 | 11 | bool isLongPressedName(char *name, char *typed) { 12 | char *p1 = name, *p2 = typed; 13 | char last; 14 | 15 | while (*p1 || *p2) { 16 | if (*p1 == *p2) { 17 | last = *p1++; 18 | } else if (*p2 != last) { 19 | return false; 20 | } 21 | p2++; 22 | } 23 | return true; 24 | } 25 | 26 | void test(bool expect, char *name, char *typed) { 27 | EXPECT_EQ_INT(expect, isLongPressedName(name, typed)); 28 | } 29 | 30 | int main(void) { 31 | test(true, "alex", "aaleex"); 32 | test(false, "saeed", "ssaaedd"); 33 | test(true, "leelee", "lleeelee"); 34 | test(true, "laiden", "laiden"); 35 | 36 | return testOutput(); 37 | } 38 | -------------------------------------------------------------------------------- /c/200-299/283-move-zeroes.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 冒泡排序的思路来解即可. 6 | */ 7 | 8 | #include "c/data-structures/array.h" 9 | #include "c/test.h" 10 | 11 | void swap(int *a, int *b) { 12 | int tmp = *a; 13 | *a = *b; 14 | *b = tmp; 15 | } 16 | 17 | void moveZeroes(int *nums, int numsSize) { 18 | for (int i = 0, j = 0; i < numsSize; i++) { 19 | if (nums[i] != 0) { 20 | swap(&nums[i], &nums[j++]); 21 | } 22 | } 23 | } 24 | 25 | void test(const char *expect, char *s) { 26 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 27 | moveZeroes(arrayValue(e), arraySize(e)); 28 | 29 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString(e)); 30 | 31 | arrayFree(e); 32 | } 33 | 34 | int main(void) { 35 | test("[1,3,12,0,0]", "[0,1,0,3,12]"); 36 | 37 | return testOutput(); 38 | } 39 | -------------------------------------------------------------------------------- /c/1600-1699/1680-concatenation-of-consecutive-binary-numbers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * f(1) = 1 6 | * f(2) = (f(1) << bitLen(2)) + 2 7 | * f(3) = (f(2) << bitLen(3)) + 3 8 | * ... 9 | * f(n) = (f(n-1) << bitLen(n)) + n 10 | */ 11 | 12 | #include 13 | #include 14 | #include "c/test.h" 15 | 16 | int concatenatedBinary(int n) { 17 | int64_t res = 1; 18 | int count = 1; 19 | for (int i = 2; i <= n; i++) { 20 | if ((i & (i - 1)) == 0) count++; /** 参考别人的写法, 用在这里很巧妙 */ 21 | res = ((res << count) | i) % 1000000007; 22 | } 23 | return res; 24 | } 25 | 26 | void test(int expect, int n) { 27 | EXPECT_EQ_INT(expect, concatenatedBinary(n)); 28 | } 29 | 30 | int main(void) { 31 | test(1, 1); 32 | test(27, 3); 33 | test(505379714, 12); 34 | 35 | return testOutput(); 36 | } 37 | -------------------------------------------------------------------------------- /c/200-299/268-missing-number.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * https://leetcode.com/problems/missing-number/ 6 | * Q: 一个长度为n的数字, 元素是[0, n], 每个数字仅出现一次, 找到那个缺失的数字 7 | * 8 | * 简单的加减运算就能找到缺失的数字 9 | */ 10 | 11 | #include "c/data-structures/array.h" 12 | #include "c/test.h" 13 | 14 | int missingNumber(int *nums, int numsSize) { 15 | int n = 0; 16 | for (int i = 0; i < numsSize; i++) { 17 | n += i + 1 - nums[i]; 18 | } 19 | return n; 20 | } 21 | 22 | void test(int except, const char *nums) { 23 | arrayEntry *e = arrayParse1D(nums, ARRAY_INT); 24 | 25 | EXPECT_EQ_INT(except, missingNumber(arrayValue(e), arraySize(e))); 26 | 27 | arrayFree(e); 28 | } 29 | 30 | int main(void) { 31 | test(2, "[3,0,1]"); 32 | test(2, "[0,1]"); 33 | test(8, "[9,6,4,2,3,5,7,0,1]"); 34 | 35 | return testOutput(); 36 | } 37 | -------------------------------------------------------------------------------- /c/tools/stack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/tools/stack.h" 7 | #include /* assert() */ 8 | #include /* realloc() */ 9 | 10 | context stackMake(void) { 11 | context c; 12 | c.stack = NULL; 13 | c.size = c.top = 0; 14 | return c; 15 | } 16 | 17 | void *stackPush(context *c, size_t size) { 18 | assert(size > 0); 19 | if (c->top + size >= c->size) { 20 | if (c->size == 0) c->size = STACK_INIT_SIZE; 21 | while (c->top + size >= c->size) { 22 | c->size += c->size >> 1; /* c->size * 1.5 */ 23 | } 24 | c->stack = (char *)realloc(c->stack, c->size); 25 | } 26 | 27 | c->top += size; 28 | return c->stack + c->top - size; 29 | } 30 | 31 | void *stackPop(context *c, size_t size) { 32 | assert(size > 0); 33 | c->top -= size; 34 | return c->stack + c->top; 35 | } 36 | -------------------------------------------------------------------------------- /c/000-099/55-jump-game.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 标记一个不可达的计数, 从后向前查找, 找不到加1, 找到置0, 最后判断计数是否等于0 6 | */ 7 | 8 | #include 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | bool canJump(int *nums, int numsSize) { 13 | int flag = 0; 14 | for (int i = numsSize - 2; i >= 0; i--) { 15 | flag = nums[i] <= flag ? flag + 1 : 0; 16 | } 17 | 18 | return flag == 0; 19 | } 20 | 21 | void test(bool expect, char *s) { 22 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 23 | 24 | EXPECT_EQ_INT(expect, canJump(arrayValue(e), arraySize(e))); 25 | 26 | arrayFree(e); 27 | } 28 | 29 | int main(void) { 30 | test(true, "[2,3,1,1,4]"); 31 | test(false, "[3,2,1,0,4]"); 32 | 33 | test(true, "[0]"); 34 | test(true, "[3,0,0,0]"); 35 | test(false, "[1,1,0,1]"); 36 | 37 | return testOutput(); 38 | } 39 | -------------------------------------------------------------------------------- /c/200-299/201-bitwise-and-of-numbers-range.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 朴素方法提交后超时, 那这就是其他的解法了 6 | * 没有思路... 7 | * 看了讨论后, 终于理解了 8 | * 这样想象, 把所有的数字竖着排开, 如果某一位有0, 则从结果来看这一位肯定为0 9 | * 理论是这样 10 | * 但从代码的角度来看 11 | * 就是, 两个数字不断右移, 记录移动的次数, 直到两个数字相等停止 12 | * 其实就是求两个数最高位相等部分, 然后其他地方填0 13 | */ 14 | 15 | #include "c/data-structures/array.h" 16 | #include "c/test.h" 17 | 18 | int rangeBitwiseAnd(int m, int n) { 19 | int count = 0; 20 | while (m != n) { 21 | m >>= 1, n >>= 1, count++; 22 | } 23 | return m << count; 24 | } 25 | 26 | void test(int expect, char *s) { 27 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 28 | int *nums = (int *)arrayValue(e); 29 | EXPECT_EQ_INT(expect, rangeBitwiseAnd(nums[0], nums[1])); 30 | arrayFree(e); 31 | } 32 | 33 | int main(void) { 34 | test(4, "[5,7]"); 35 | test(0, "[0,1]"); 36 | 37 | return testOutput(); 38 | } 39 | -------------------------------------------------------------------------------- /c/000-099/09-palindrome-number.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 先说几个特殊情况: 6 | * 1. 0是会文数 7 | * 2. 负数不是回文数 8 | * 3. 可以整除10的不是回文数 9 | * 其他情况下, 把 x 切成两半, 一半反转, 另一半正常, 10 | * 当两个数相等(1221) 或 较大数除10等于较小数(121), 是回文数. 反之不是 11 | */ 12 | 13 | #include 14 | #include "c/test.h" 15 | 16 | bool isPalindrome(int x) { 17 | if (x == 0) return true; 18 | if (x < 0 || x % 10 == 0) return false; 19 | int tmp = 0; 20 | while (x > tmp) { 21 | tmp = tmp * 10 + x % 10; 22 | x /= 10; 23 | } 24 | return x == tmp || x == tmp / 10; 25 | } 26 | 27 | void test(bool expect, int x) { 28 | EXPECT_EQ_INT(expect, isPalindrome(x)); 29 | } 30 | 31 | int main(void) { 32 | test(true, 0); 33 | test(true, 11); 34 | test(true, 121); 35 | test(true, 1221); 36 | 37 | test(false, -1); 38 | test(false, 1211); 39 | test(false, 10); 40 | 41 | return testOutput(); 42 | } 43 | -------------------------------------------------------------------------------- /c/000-099/28-implement-strstr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 暴力解决. 6 | */ 7 | 8 | #include /* strlen(), strstr() */ 9 | #include "c/test.h" 10 | 11 | int strStr(char *haystack, char *needle) { 12 | int len1 = strlen(haystack), 13 | len2 = strlen(needle); 14 | if (len2 > len1) return -1; 15 | 16 | int i, j, k; 17 | for (i = 0; i < len1 - len2 + 1; i++) { 18 | for (k = i, j = 0; haystack[k] == needle[j] && j < len2; k++, j++) {} 19 | if (j == len2) return i; 20 | } 21 | return -1; 22 | } 23 | 24 | void test(char *haystack, char *needle) { 25 | int expect = -1; 26 | char* pos = strstr(haystack, needle); 27 | if (pos) expect = pos - haystack; 28 | 29 | EXPECT_EQ_INT(expect, strStr(haystack, needle)); 30 | } 31 | 32 | int main(void) { 33 | test("Hello World.", "World"); 34 | test("Hello World.", "Word"); 35 | 36 | return testOutput(); 37 | } 38 | -------------------------------------------------------------------------------- /c/1100-1199/1108-defanging-an-ip-address.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 基本的字符还替换问题. 6 | */ 7 | 8 | #include /* malloc() */ 9 | #include /* strlen() */ 10 | #include "c/test.h" 11 | 12 | char *defangIPaddr(char *address) { 13 | char *rtn = malloc(sizeof(char) * (strlen(address) + 3 * 2 + 1)); 14 | char *p1 = address, *p2 = rtn; 15 | while (*p1 != '\0') { 16 | if (*p1 == '.') { 17 | *p2++ = '['; 18 | *p2++ = '.'; 19 | *p2++ = ']'; 20 | } else { 21 | *p2++ = *p1; 22 | } 23 | p1++; 24 | } 25 | *p2 = '\0'; 26 | return rtn; 27 | } 28 | 29 | void test(const char *expect, char *address) { 30 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, defangIPaddr(address)); 31 | } 32 | 33 | int main(void) { 34 | test("1[.]1[.]1[.]1", "1.1.1.1"); 35 | test("255[.]100[.]50[.]0", "255.100.50.0"); 36 | 37 | return testOutput(); 38 | } 39 | -------------------------------------------------------------------------------- /c/500-599/560-subarray-sum-equals-k.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 暴力破解, 时间复杂度: O(n^2), 提交后比较耗时. 6 | * 7 | * 看了解答方案后, 使用 HashMap 的时间复杂度为: O(n) 8 | * TODO: 后续引入 HashMap 后再优化 9 | */ 10 | 11 | #include "c/data-structures/array.h" 12 | #include "c/test.h" 13 | 14 | int subarraySum(int *nums, int numsSize, int k) { 15 | int count = 0; 16 | for (int i = 0; i < numsSize; i++) { 17 | for (int j = i, sum = 0; j < numsSize && sum < k; j++) { 18 | sum += nums[j]; 19 | if (sum == k) { 20 | ++count; 21 | } 22 | } 23 | } 24 | return count; 25 | } 26 | 27 | void test(int expect, char *nums, int k) { 28 | arrayEntry *e = arrayParse1D(nums, ARRAY_INT); 29 | EXPECT_EQ_INT(expect, subarraySum(arrayValue(e), arraySize(e), k)); 30 | arrayFree(e); 31 | } 32 | 33 | int main(void) { 34 | test(2, "[1,1,1]", 2); 35 | 36 | return testOutput(); 37 | } 38 | -------------------------------------------------------------------------------- /c/200-299/264-ugly-number-ii.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 考虑一下规则, 下一个 uglyNumber 一定是之前某一个 uglyNumber 乘2, 乘3, 乘5 得到的. 6 | * 剩下就是动态规划的问题了. 7 | */ 8 | 9 | #include "c/test.h" 10 | 11 | int min(int a, int b, int c) { 12 | int tmp = a <= b ? a : b; 13 | return tmp <= c ? tmp : c; 14 | } 15 | 16 | int nthUglyNumber(int n) { 17 | if (n == 0) return 0; 18 | int dp[n]; 19 | dp[0] = 1; /* 初始值为0 */ 20 | int p2 = 0, p3 = 0, p5 = 0; 21 | for (int i = 1; i < n; i++) { 22 | dp[i] = min(dp[p2] * 2, dp[p3] * 3, dp[p5] * 5); 23 | if (dp[p2] * 2 == dp[i]) p2++; 24 | if (dp[p3] * 3 == dp[i]) p3++; 25 | if (dp[p5] * 5 == dp[i]) p5++; 26 | } 27 | return dp[n - 1]; 28 | } 29 | 30 | void test(int expect, int n) { 31 | EXPECT_EQ_INT(expect, nthUglyNumber(n)); 32 | } 33 | 34 | int main(void) { 35 | test(12, 10); 36 | 37 | test(15, 11); 38 | 39 | return testOutput(); 40 | } 41 | -------------------------------------------------------------------------------- /c/000-099/11-container-with-most-water.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 装水面积 = 两个竖线的距离 x 较短竖线的长度 6 | * 所以从两头往中间找最大的装水面积 7 | */ 8 | 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 13 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 14 | int maxArea(int *height, int heightSize) { 15 | int i = 0, 16 | j = heightSize - 1, 17 | rt = 0; 18 | 19 | while (i < j) { 20 | rt = MAX(rt, (j - i) * MIN(height[i], height[j])); 21 | height[i] <= height[j] ? i++ : j--; 22 | } 23 | 24 | return rt; 25 | } 26 | 27 | void test(int expect, const char *str) { 28 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 29 | 30 | EXPECT_EQ_INT(expect, maxArea(arrayValue(e), arraySize(e))); 31 | 32 | arrayFree(e); 33 | } 34 | 35 | int main(void) { 36 | test(1, "[1, 1]"); 37 | test(0, "[0, 2]"); 38 | 39 | return testOutput(); 40 | } 41 | -------------------------------------------------------------------------------- /c/000-099/35-search-insert-position.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 就是简单的二分查找 6 | */ 7 | 8 | #include "c/data-structures/array.h" 9 | #include "c/test.h" 10 | 11 | int searchInsert(int *nums, int numsSize, int target) { 12 | int a = 0, b = numsSize - 1; 13 | while (a <= b) { 14 | int i = (a + b) / 2; 15 | if (nums[i] > target) { 16 | b = i - 1; 17 | } else if (nums[i] < target) { 18 | a = i + 1; 19 | } else { 20 | return i; 21 | } 22 | } 23 | return a; 24 | } 25 | 26 | void test(int expect, const char *nums, int target) { 27 | arrayEntry *e = arrayParse1D(nums, ARRAY_INT); 28 | 29 | EXPECT_EQ_INT(expect, searchInsert(arrayValue(e), arraySize(e), target)); 30 | 31 | arrayFree(e); 32 | } 33 | 34 | int main(void) { 35 | test(2, "[1,3,5,6]", 5); 36 | test(1, "[1,3,5,6]", 2); 37 | test(4, "[1,3,5,6]", 7); 38 | test(0, "[1,3,5,6]", 0); 39 | 40 | return testOutput(); 41 | } -------------------------------------------------------------------------------- /c/300-399/344-reverse-string.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * https://leetcode.com/problems/reverse-string/ 6 | * 翻转字符串, 原地修改, 不占用空间 7 | * 8 | * 非常基本操作 9 | */ 10 | 11 | #include /* malloc() */ 12 | #include /* strlen(), memcpy() */ 13 | #include "c/test.h" 14 | 15 | void swap(char *a, char *b) { 16 | char tmp = *a; 17 | *a = *b; 18 | *b = tmp; 19 | } 20 | 21 | void reverseString(char* s, int sSize) { 22 | int p = 0, q = sSize - 1; 23 | while (p < q) { 24 | swap(&s[p++], &s[q--]); 25 | } 26 | } 27 | 28 | void test(const char *expect, const char *str) { 29 | int len = strlen(str); 30 | char *s = malloc(sizeof(char) * (len + 1)); 31 | memcpy(s, str, len + 1); 32 | s[len] = '\0'; 33 | 34 | reverseString(s, len); 35 | 36 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, s); 37 | } 38 | 39 | int main(void) { 40 | test("olleh", "hello"); 41 | 42 | return testOutput(); 43 | } 44 | -------------------------------------------------------------------------------- /c/000-099/24-swap-nodes-in-pairs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 看到如此优雅的版本, 就不贴我那屎一样的代码, 虽然它也ac了... 6 | */ 7 | 8 | #include "c/data-structures/linked-list.h" 9 | #include "c/test.h" 10 | 11 | /** 12 | * Definition for singly-linked list. 13 | * struct ListNode { 14 | * int val; 15 | * struct ListNode *next; 16 | * }; 17 | */ 18 | struct ListNode *swapPairs(struct ListNode *head) { 19 | struct ListNode **p = &head, *a, *b; 20 | while ((a = *p) && (b = a->next)) { 21 | a->next = b->next; 22 | b->next = a; 23 | *p = b; 24 | p = &(a->next); 25 | } 26 | return head; 27 | } 28 | 29 | void test(const char *expect, const char *s) { 30 | struct ListNode *list = swapPairs(linkedlistParse(s)); 31 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, linkedlistToString(list)); 32 | 33 | linkedlistFree(list); 34 | } 35 | 36 | int main(void) { 37 | test("[2,1,4,3]", "[1,2,3,4]"); 38 | 39 | return testOutput(); 40 | } 41 | -------------------------------------------------------------------------------- /c/500-599/540-single-element-in-a-sorted-array.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 题目规定了时间复杂度为 O(log n) ,所以一定是二分法查找 6 | * 注意 mid 为奇数或偶数时,会有差异 7 | */ 8 | 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | int singleNonDuplicate(int *nums, int numsSize) { 13 | int start = 0, 14 | end = numsSize - 1; 15 | while (start < end) { 16 | int mid = (start + end) / 2; 17 | if (mid % 2 == 0) 18 | mid--; 19 | if (nums[mid] == nums[mid + 1]) 20 | end = mid - 1; 21 | else 22 | start = mid + 1; 23 | } 24 | return nums[start]; 25 | } 26 | 27 | void test(int expect, const char *str) { 28 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 29 | 30 | EXPECT_EQ_INT(expect, singleNonDuplicate(arrayValue(e), arraySize(e))); 31 | 32 | arrayFree(e); 33 | } 34 | 35 | int main(void) { 36 | test(2, "[1,1,2,3,3,4,4,8,8]"); 37 | test(10, "[3,3,7,7,10,11,11]"); 38 | 39 | return testOutput(); 40 | } 41 | -------------------------------------------------------------------------------- /c/100-199/112-path-sum.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 递归思想即可, 注意只要叶子才算数 6 | */ 7 | 8 | #include 9 | #include "c/data-structures/binary-tree.h" 10 | #include "c/test.h" 11 | 12 | bool hasPathSum(struct TreeNode *root, int targetSum) { 13 | if (root == NULL) { 14 | return false; 15 | } 16 | 17 | if (!root->left && !root->right) { 18 | return targetSum == root->val; 19 | } 20 | 21 | return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val); 22 | } 23 | 24 | void test(bool expect, const char *rootStr, int targetSum) { 25 | struct TreeNode *root = treeParse(rootStr); 26 | 27 | EXPECT_EQ_INT(expect, hasPathSum(root, targetSum)); 28 | 29 | treeFree(root); 30 | } 31 | 32 | int main(void) { 33 | test(true, "[5,4,8,11,null,13,4,7,2,null,null,null,1]", 22); 34 | test(false, "[1,2,3]", 5); 35 | test(false, "[]", 0); 36 | 37 | test(false, "[1,2]", 1); 38 | 39 | return testOutput(); 40 | } 41 | -------------------------------------------------------------------------------- /c/100-199/191-number-of-1-bits.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 第一次想到的当然是蛮力, 完成后, 在讨论帖子发现了巧妙的解法 6 | * 即: 每次做 x & x-1 运算时, 最后一位的'1'将被移除, 当 x == 0 时, 运算了几次就有多少个'1' 7 | */ 8 | 9 | #include 10 | #include "c/test.h" 11 | 12 | int hammingWeight(uint32_t n) { 13 | int weight = 0; 14 | while (n) { 15 | weight += (n & 1); 16 | n >>= 1; 17 | } 18 | return weight; 19 | } 20 | 21 | int hammingWeight_v2(uint32_t n) { 22 | int weight = 0; 23 | while (n) { 24 | n &= n - 1; 25 | weight++; 26 | } 27 | return weight; 28 | } 29 | 30 | void test(int expect, uint32_t n) { 31 | EXPECT_EQ_INT(expect, hammingWeight(n)); 32 | EXPECT_EQ_INT(expect, hammingWeight_v2(n)); 33 | } 34 | 35 | int main(void) { 36 | // 0000 0000 0000 0000 0000 0000 0000 1011 37 | test(3, 0xB); 38 | // 0000 0000 0000 0000 0000 0000 1000 0000 39 | test(1, 0x80); 40 | // 1111 1111 1111 1111 1111 1111 1111 1101 41 | test(31, 0xFFFFFFFD); 42 | 43 | return testOutput(); 44 | } 45 | -------------------------------------------------------------------------------- /c/700-799/704-binary-search.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * https://leetcode.com/problems/binary-search/ 6 | * Q: 就是二分查找 7 | * 8 | * 好久没写二分查找了, 虽然道理都懂, 但写起来却需要借助测试用例 9 | */ 10 | 11 | #include "c/data-structures/array.h" 12 | #include "c/test.h" 13 | 14 | int search(int *nums, int numsSize, int target) { 15 | int l = 0, h = numsSize - 1; 16 | while (l <= h) { 17 | int m = (l + h) / 2; 18 | if (nums[m] == target) { 19 | return m; 20 | } else if (nums[m] < target) { 21 | l = m + 1; 22 | } else { 23 | h = m - 1; 24 | } 25 | } 26 | return -1; 27 | } 28 | 29 | void test(int expect, char *nums, int target) { 30 | arrayEntry *e = arrayParse1D(nums, ARRAY_INT); 31 | 32 | EXPECT_EQ_INT(expect, search(arrayValue(e), arraySize(e), target)); 33 | 34 | arrayFree(e); 35 | } 36 | 37 | int main(void) { 38 | test(4, "[-1,0,3,5,9,12]", 9); 39 | test(-1, "[-1,0,3,5,9,12]", 2); 40 | 41 | test(0, "[5]", 5); 42 | 43 | return testOutput(); 44 | } 45 | -------------------------------------------------------------------------------- /c/000-099/10-regular-expression-matching.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 递归解法 6 | */ 7 | 8 | #include 9 | #include "c/test.h" 10 | 11 | bool matchFirst(char *s, char *p) { 12 | return (*p == '.' && *s != '\0') || *s == *p; 13 | } 14 | 15 | bool isMatch(char *s, char *p) { 16 | if (*p == '\0') return *s == '\0'; 17 | 18 | if (*(p+1) != '*') { 19 | if (!matchFirst(s, p)) return false; 20 | return isMatch(s+1, p+1); 21 | } else { 22 | do { 23 | if (isMatch(s, p+2)) return true; /* 先尝试匹配'_*'之后的部分 */ 24 | } while (matchFirst(s++, p)); 25 | return false; 26 | } 27 | } 28 | 29 | void test(bool expect, char *s, char *p) { 30 | EXPECT_EQ_INT(expect, isMatch(s, p)); 31 | } 32 | 33 | int main(void) { 34 | test(false, "aa", "a"); 35 | test(true, "aa", "aa"); 36 | test(false, "aaa", "aa"); 37 | test(true, "aa", "a*"); 38 | test(true, "aa", ".*"); 39 | test(true, "ab", ".*"); 40 | test(true, "aab", "c*a*b*"); 41 | 42 | return testOutput(); 43 | } 44 | -------------------------------------------------------------------------------- /c/1000-1099/1046-last-stone-weight.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 排序后按照规则不断循环即可. 6 | */ 7 | 8 | #include /* qsort() */ 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | #include "c/tools/compare.h" 12 | 13 | int lastStoneWeight(int *stones, int stonesSize) { 14 | qsort(stones, stonesSize, sizeof(int), compare_ints); 15 | 16 | for (stonesSize -= 2; stonesSize >= 0; stonesSize -= 2) { 17 | int x = stones[stonesSize], y = stones[stonesSize + 1]; 18 | if (x != y) { 19 | stones[stonesSize++] = y - x; 20 | qsort(stones, stonesSize + 1, sizeof(int), compare_ints); 21 | } 22 | } 23 | return stonesSize == -1 ? stones[0] : 0; 24 | } 25 | 26 | void test(int expect, char *s) { 27 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 28 | EXPECT_EQ_INT(expect, lastStoneWeight(arrayValue(e), arraySize(e))); 29 | arrayFree(e); 30 | } 31 | 32 | int main(void) { 33 | test(1, "[2,7,4,1,8,1]"); 34 | 35 | test(2, "[1,3]"); 36 | 37 | return testOutput(); 38 | } 39 | -------------------------------------------------------------------------------- /c/500-599/557-reverse-words-in-a-string-iii.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 先找到' ' 和 '\0' 的位置, 然后开始逆转 6 | */ 7 | 8 | #include /* malloc() */ 9 | #include /* strchr(), strlen(s) */ 10 | #include "c/test.h" 11 | 12 | void swap(char *a, char *b) { 13 | char tmp = *a; 14 | *a = *b; 15 | *b = tmp; 16 | } 17 | 18 | char *reverseWords(char *s) { 19 | char *p1 = s, *p2, *c; 20 | do { 21 | c = strchr(p1, ' '); 22 | p2 = (c ? c - 1 : s + strlen(s) - 1); 23 | while (p1 < p2) 24 | swap(p1++, p2--); 25 | p1 = c + 1; 26 | } while (c); 27 | return s; 28 | } 29 | 30 | void test(const char *expect, const char *str) { 31 | int len = strlen(str); 32 | char *s = malloc(sizeof(char) * (len + 1)); 33 | memcpy(s, str, len + 1); 34 | s[len] = '\0'; 35 | 36 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, reverseWords(s)); 37 | } 38 | 39 | int main(void) { 40 | test("s'teL ekat edoCteeL tsetnoc", 41 | "Let's take LeetCode contest"); 42 | 43 | return testOutput(); 44 | } 45 | -------------------------------------------------------------------------------- /c/200-299/230-kth-smallest-element-in-a-bst.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 首先 BST 的前序遍历是有序的, 然后二分查找的思路 6 | */ 7 | 8 | #include "c/data-structures/binary-tree.h" 9 | #include "c/test.h" 10 | 11 | /** 12 | * Definition for a binary tree node. 13 | * struct TreeNode { 14 | * int val; 15 | * struct TreeNode *left; 16 | * struct TreeNode *right; 17 | * }; 18 | */ 19 | int kthSmallest(struct TreeNode *root, int k) { 20 | int count = treeCount(root->left) + 1; 21 | if (count > k) { 22 | return kthSmallest(root->left, k); 23 | } else if (count < k) { 24 | return kthSmallest(root->right, k - count); 25 | } else { 26 | return root->val; 27 | } 28 | } 29 | 30 | void test(int expect, const char *str, int k) { 31 | struct TreeNode *root = treeParse(str); 32 | 33 | EXPECT_EQ_INT(expect, kthSmallest(root, k)); 34 | 35 | treeFree(root); 36 | } 37 | 38 | int main(void) { 39 | test(1, "[3,1,4,null,2]", 1); 40 | test(3, "[5,3,6,2,4,null,null,1]", 3); 41 | 42 | return testOutput(); 43 | } 44 | -------------------------------------------------------------------------------- /c/1000-1099/1051-height-checker.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 看了好几遍也没看懂题目的意思, 直到看了第一条提示, 6 | * 竟然要跟有序的数组对比, 不同数字的个数... 7 | */ 8 | 9 | #include /* malloc(), free(), qsort() */ 10 | #include /* memcpy() */ 11 | #include "c/data-structures/array.h" 12 | #include "c/test.h" 13 | #include "c/tools/compare.h" 14 | 15 | int heightChecker(int *heights, int heightsSize) { 16 | int *p = malloc(sizeof(int) * heightsSize); 17 | memcpy(p, heights, sizeof(int) * heightsSize); 18 | qsort(p, heightsSize, sizeof(int), compare_ints); 19 | 20 | int move = 0; 21 | for (int i = 0; i < heightsSize; i++) { 22 | if (heights[i] != p[i]) { 23 | ++move; 24 | } 25 | } 26 | free(p); 27 | return move; 28 | } 29 | 30 | void test(int expect, char *s) { 31 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 32 | 33 | EXPECT_EQ_INT(expect, heightChecker(arrayValue(e), arraySize(e))); 34 | 35 | arrayFree(e); 36 | } 37 | 38 | int main(void) { 39 | test(3, "[1,1,4,2,1,3]"); 40 | 41 | return testOutput(); 42 | } 43 | -------------------------------------------------------------------------------- /c/500-599/541-reverse-string-ii.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 在 344 的基础上, 加上 k 的判断, 注意 k 和 len 的大小 6 | */ 7 | 8 | #include /* malloc() */ 9 | #include /* strlen(), memcpy() */ 10 | #include "c/test.h" 11 | 12 | void swap(char *a, char *b) { 13 | char tmp = *a; 14 | *a = *b; 15 | *b = tmp; 16 | } 17 | 18 | #define MIN(a, b) ((a) <= (b) ? (a) : (b)) 19 | char *reverseStr(char *s, int k) { 20 | int len = strlen(s); 21 | char *p1, *p2; 22 | for (int i = 0; i < len; i += 2 * k) { 23 | p1 = s + i; 24 | p2 = s + MIN(i + k - 1, len - 1); 25 | while (p1 < p2) 26 | swap(p1++, p2--); 27 | } 28 | return s; 29 | } 30 | 31 | void test(const char *expect, const char *str, int k) { 32 | int len = strlen(str); 33 | char *s = malloc(sizeof(char) * (len + 1)); 34 | memcpy(s, str, len + 1); 35 | s[len] = '\0'; 36 | 37 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, reverseStr(s, k)); 38 | } 39 | 40 | int main(void) { 41 | test("bacdfeg", "abcdefg", 2); 42 | 43 | return testOutput(); 44 | } 45 | -------------------------------------------------------------------------------- /c/tools/stack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #ifndef C_TOOLS_STACK_H_ 7 | #define C_TOOLS_STACK_H_ 8 | 9 | #include /* memcpy() */ 10 | 11 | #ifndef STACK_INIT_SIZE 12 | #define STACK_INIT_SIZE 64 13 | #endif 14 | 15 | #define PUSH(c, v) do { *(context *)stackPush(c, sizeof(context)) = (v);} while (0) 16 | #define PUSHC(c, v) do { *(char *)stackPush(c, sizeof(char)) = (v); } while (0) 17 | #define PUSHI(c, v) do { *(int *)stackPush(c, sizeof(int)) = (v); } while (0) 18 | #define PUSHD(c, v) do { *(double *)stackPush(c, sizeof(double)) = (v); } while (0) 19 | #define PUSHCP(c, v) do { *(char **)stackPush(c, sizeof(char*)) = (v); } while (0) 20 | 21 | #define PUSHS(c, s, len) do { if (len > 0) memcpy(stackPush(c, len), s, len); } while (0) 22 | 23 | typedef struct { 24 | char *stack; 25 | size_t size, top; 26 | } context; 27 | 28 | context stackMake(void); 29 | void *stackPush(context *c, size_t size); 30 | void *stackPop(context *c, size_t size); 31 | 32 | #endif /* C_TOOLS_STACK_H_ */ 33 | -------------------------------------------------------------------------------- /c/algorithms/sort-merge.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/algorithms/sort.h" 7 | 8 | #include /* INT32_MAX */ 9 | #include /* malloc(), free() */ 10 | 11 | static void merge(int *a, int p, int q, int r) { 12 | int i, j, k; 13 | 14 | /* 1. 创建临时空间 */ 15 | int n1 = q - p + 1; 16 | int *L = malloc(sizeof(int) * (n1+1)); 17 | for (i = 0; i < n1; ++i) 18 | L[i] = a[p+i]; 19 | L[n1] = INT32_MAX; 20 | 21 | int n2 = r - q; 22 | int *R = malloc(sizeof(int) * (n2+1)); 23 | for (j = 0; j < n2; ++j) 24 | R[j] = a[q+j+1]; 25 | R[n2] = INT32_MAX; 26 | i = 0, j = 0; 27 | 28 | /* 2. 合并数组 */ 29 | for (k = p; k <= r; ++k) 30 | a[k] = L[i] <= R[j] ? L[i++] : R[j++]; 31 | 32 | /* 3. 释放临时空间 */ 33 | free(L); 34 | free(R); 35 | } 36 | 37 | static void sort(int *a, int p, int r) { 38 | if (p >= r) return; 39 | int q = (p + r) / 2; 40 | sort(a, p, q); 41 | sort(a, q+1, r); 42 | merge(a, p, q, r); 43 | } 44 | 45 | void sortMerge(int *a, int len) { 46 | sort(a, 0, len - 1); 47 | } 48 | -------------------------------------------------------------------------------- /c/000-099/53-maximum-subarray.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 题目要求时间复杂度O(n), 所以一定是一层循环. 6 | * 按照动态规划的思路, 手写一下计算过程, 代码就很好写啦. 7 | * 8 | * -2, 1, -3, 4, -1, 2, 1, -5, 4 9 | * -2 10 | * 1 11 | * -2 12 | * 4 13 | * 3 14 | * 5 15 | * 6 <- 最大 16 | * 1 17 | * 5 18 | */ 19 | 20 | #include "c/data-structures/array.h" 21 | #include "c/test.h" 22 | 23 | int maxSubArray(int *nums, int numsSize) { 24 | int max = nums[0], cur = nums[0]; 25 | for (int i = 1; i < numsSize; i++) { 26 | cur = nums[i] + cur > nums[i] ? cur + nums[i] : nums[i]; 27 | if (cur > max) max = cur; 28 | } 29 | return max; 30 | } 31 | 32 | void test(int expect, char *s) { 33 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 34 | 35 | EXPECT_EQ_INT(expect, maxSubArray(arrayValue(e), arraySize(e))); 36 | 37 | arrayFree(e); 38 | } 39 | 40 | int main(void) { 41 | test(6, "[-2,1,-3,4,-1,2,1,-5,4]"); 42 | 43 | return testOutput(); 44 | } 45 | -------------------------------------------------------------------------------- /c/000-099/42-trapping-rain-water.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 维持首尾两个指针, 和首尾的最大高度, 然后向中间寻找 6 | * 如果遇到'坑', 就把'坑'的深度累加到结果中 7 | */ 8 | 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | int trap(int *height, int heightSize) { 13 | int rtn = 0, 14 | left_max = 0, right_max = 0, 15 | left = 0, right = heightSize - 1; 16 | 17 | while (left < right) { 18 | if (height[left] < height[right]) { 19 | height[left] >= left_max ? (left_max = height[left]) : (rtn += left_max - height[left]); 20 | ++left; 21 | } else { 22 | height[right] >= right_max ? (right_max = height[right]) : (rtn += right_max - height[right]); 23 | --right; 24 | } 25 | } 26 | return rtn; 27 | } 28 | 29 | void test(int expect, const char *str) { 30 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 31 | 32 | EXPECT_EQ_INT(expect, trap(arrayValue(e), (arraySize(e)))); 33 | 34 | arrayFree(e); 35 | } 36 | 37 | int main(void) { 38 | test(6, "[0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]"); 39 | 40 | return testOutput(); 41 | } 42 | -------------------------------------------------------------------------------- /c/200-299/202-happy-number.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 维护一个数组, 放入曾经计算过的值, 如果重复, 则失败. 6 | */ 7 | 8 | #include 9 | #include 10 | #include "c/test.h" 11 | 12 | struct Data { 13 | int arr[64]; 14 | int size; 15 | }; 16 | 17 | void add(struct Data *data, int value) { 18 | data->arr[data->size++] = value; 19 | } 20 | 21 | bool contains(struct Data *data, int value) { 22 | for (int i = 0; i < data->size; i++) { 23 | if (data->arr[i] == value) { 24 | return true; 25 | } 26 | } 27 | return false; 28 | } 29 | 30 | bool isHappy(int n) { 31 | struct Data data = {{}, 0}; 32 | 33 | while (n != 1) { 34 | int sum = 0; 35 | while (n) { 36 | sum += pow(n % 10, 2); 37 | n /= 10; 38 | } 39 | if (contains(&data, sum)) return false; 40 | add(&data, n = sum); 41 | } 42 | return true; 43 | } 44 | 45 | void test(bool expect, int n) { 46 | EXPECT_EQ_INT(expect, isHappy(n)); 47 | } 48 | 49 | int main(void) { 50 | test(false, 2); 51 | test(true, 19); 52 | 53 | return testOutput(); 54 | } 55 | -------------------------------------------------------------------------------- /c/000-099/75-sort-colors.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * Q: Could you come up with a one-pass algorithm using only constant space? 6 | * 7 | * 分组的思路 8 | * 遍历一遍数组, 将0放入数组前半部分, 将2放入数组后半部分 9 | */ 10 | 11 | #include "c/data-structures/array.h" 12 | #include "c/test.h" 13 | 14 | void swap(int *a, int *b) { 15 | int tmp = *a; *a = *b; *b = tmp; 16 | } 17 | 18 | void sortColors(int *nums, int numsSize) { 19 | int i = 0, p0 = -1, p2 = numsSize; 20 | while (i < p2) { 21 | if (nums[i] == 0) { 22 | swap(&nums[++p0], &nums[i++]); 23 | } else if (nums[i] == 1) { 24 | i++; 25 | } else if (nums[i] == 2) { 26 | swap(&nums[--p2], &nums[i]); 27 | } 28 | } 29 | } 30 | 31 | void test(const char *expect, const char *str) { 32 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 33 | sortColors(arrayValue(e), arraySize(e)); 34 | 35 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString(e)); 36 | 37 | arrayFree(e); 38 | } 39 | 40 | int main(void) { 41 | test("[0,0,1,1,2,2]", "[2,0,2,1,1,0]"); 42 | 43 | return testOutput(); 44 | } 45 | -------------------------------------------------------------------------------- /c/500-599/543-diameter-of-binary-tree.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 想知道叶子之间的最大距离, 那么最终的结果一定是某个节点的左结点高度+右节点高度 6 | * 因此中间数据应该是当前节点的高度 7 | * 后序遍历, 同时维护一个最大距离 8 | */ 9 | 10 | #include "c/data-structures/binary-tree.h" 11 | #include "c/test.h" 12 | 13 | int walk(struct TreeNode *root, int *max) { 14 | if (root == NULL) { 15 | return 0; 16 | } 17 | 18 | int left = walk(root->left, max); 19 | int right = walk(root->right, max); 20 | 21 | if (*max < left + right) { 22 | *max = left + right; 23 | } 24 | return (left > right ? left : right) + 1; 25 | } 26 | 27 | int diameterOfBinaryTree(struct TreeNode *root) { 28 | int max = 0; 29 | walk(root, &max); 30 | return max; 31 | } 32 | 33 | void test(int expect, char *s) { 34 | struct TreeNode *root = treeParse(s); 35 | EXPECT_EQ_INT(expect, diameterOfBinaryTree(root)); 36 | treeFree(root); 37 | } 38 | 39 | int main(void) { 40 | test(3, "[1,2,3,4,5]"); 41 | 42 | test(5, "[1,2,3,4,5,null,6,null,null,7,8]"); 43 | test(3, "[4,1,null,2,null,3]"); 44 | 45 | return testOutput(); 46 | } 47 | -------------------------------------------------------------------------------- /c/500-599/530-minimum-absolute-difference-in-bst.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 前序遍历二叉树, 计算最小差值即可 6 | */ 7 | 8 | #include "c/data-structures/binary-tree.h" 9 | #include "c/test.h" 10 | 11 | void walk(struct TreeNode *root, int *lastVal, int *min) { 12 | if (root->left) walk(root->left, lastVal, min); 13 | if (*lastVal >= 0) { 14 | int minus = root->val - *lastVal; 15 | if (*min > minus) { 16 | *min = minus; 17 | } 18 | } 19 | *lastVal = root->val; 20 | if (root->right) walk(root->right, lastVal, min); 21 | } 22 | 23 | int getMinimumDifference(struct TreeNode *root) { 24 | // 0 <= Node.val <= 10^5 25 | int lastVal = -1; 26 | int min = 100000 + 1; 27 | 28 | walk(root, &lastVal, &min); 29 | 30 | return min; 31 | } 32 | 33 | void test(int expect, char *str) { 34 | struct TreeNode *root = treeParse(str); 35 | EXPECT_EQ_INT(expect, getMinimumDifference(root)); 36 | treeFree(root); 37 | } 38 | 39 | int main(void) { 40 | test(1, "[4,2,6,1,3]"); 41 | test(1, "[1,0,48,null,null,12,49]"); 42 | 43 | return testOutput(); 44 | } 45 | -------------------------------------------------------------------------------- /c/600-699/605-can-place-flowers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 看似很简单的一道题, 但也挺有趣的, 因为靠边的时候规则是特殊的! 6 | */ 7 | 8 | #include 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | bool canPlaceFlowers(int *flowerbed, int flowerbedSize, int n) { 13 | int count = 1; // 开头的边界额外奖励一个, 方便循环代码计算 14 | for (int i = 0; i < flowerbedSize; i++) { 15 | if (flowerbed[i] == 0) { 16 | count++; 17 | } else if (count > 0) { 18 | n -= (count - 1) / 2; 19 | count = 0; 20 | } 21 | } 22 | 23 | // 结尾的边界更改一下计算的规则即可 24 | return (n - count / 2) <= 0; 25 | } 26 | 27 | void test(bool expect, const char *flowerbed, int n) { 28 | arrayEntry *e = arrayParse1D(flowerbed, ARRAY_INT); 29 | EXPECT_EQ_INT(expect, canPlaceFlowers(arrayValue(e), arraySize(e), n)); 30 | arrayFree(e); 31 | } 32 | 33 | int main(void) { 34 | // 示例 35 | test(true, "[1,0,0,0,1]", 1); 36 | test(false, "[1,0,0,0,1]", 2); 37 | 38 | // 提交出错 39 | test(false, "[1,0,0,0,0,1]", 2); 40 | test(true, "[0,0,1,0,1]", 1); 41 | return testOutput(); 42 | } 43 | -------------------------------------------------------------------------------- /c/100-199/165-compare-version-numbers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 最开始想用字符串分割来弄, 但 c 处理起来比较麻烦, 还是朴素方法好写一点. 6 | * 第一次提交的时候, 没有考虑 int 会越界, 后改用 int64_t 就可以了. 7 | */ 8 | 9 | #include "c/test.h" 10 | 11 | int compareVersion(char *version1, char *version2) { 12 | int64_t i1, i2; 13 | while (*version1 || *version2) { 14 | i1 = 0; 15 | while (*version1 && *version1 != '.') { 16 | i1 = i1 * 10 + *version1 - '0'; 17 | version1++; 18 | } 19 | if (*version1 == '.') version1++; 20 | 21 | i2 = 0; 22 | while (*version2 && *version2 != '.') { 23 | i2 = i2 * 10 + *version2 - '0'; 24 | version2++; 25 | } 26 | if (*version2 == '.') version2++; 27 | 28 | if (i1 != i2) return i1 < i2 ? -1 : 1; 29 | } 30 | 31 | return 0; 32 | } 33 | 34 | void test(int expect, char *version1, char *version2) { 35 | EXPECT_EQ_INT(expect, compareVersion(version1, version2)); 36 | } 37 | 38 | int main(void) { 39 | test(0, "1.01", "1.001"); 40 | test(0, "1.0", "1.0.0"); 41 | test(-1, "0.1", "1.1"); 42 | 43 | return testOutput(); 44 | } 45 | -------------------------------------------------------------------------------- /c/000/counting-elements.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 排序后, 问题就简单多了. 6 | */ 7 | 8 | #include /* qsort() */ 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | #include "c/tools/compare.h" 12 | 13 | int countElements(int *arr, int arrSize) { 14 | if (arrSize == 0) return 0; 15 | 16 | qsort(arr, arrSize, sizeof(int), compare_ints); 17 | 18 | int count = 0; 19 | int lastCount = 1; 20 | for (int i = 1; i < arrSize; i++) { 21 | if (arr[i] == arr[i - 1]) { 22 | ++lastCount; 23 | continue; 24 | } 25 | if (arr[i] == arr[i - 1] + 1) { 26 | count += lastCount; 27 | } 28 | lastCount = 1; 29 | } 30 | 31 | return count; 32 | } 33 | 34 | void test(int expect, char *s) { 35 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 36 | 37 | EXPECT_EQ_INT(expect, countElements(arrayValue(e), arraySize(e))); 38 | 39 | arrayFree(e); 40 | } 41 | 42 | int main(void) { 43 | test(2, "[1,2,3]"); 44 | test(0, "[1,1,3,3,5,5,7,7]"); 45 | test(3, "[1,3,2,3,5,0]"); 46 | test(2, "[1,1,2,2]"); 47 | 48 | return testOutput(); 49 | } 50 | -------------------------------------------------------------------------------- /c/300-399/345-reverse-vowels-of-a-string.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 两个指针, 往中间查找 6 | */ 7 | 8 | #include /* malloc() */ 9 | #include /* strlen(), strchr() */ 10 | #include "c/test.h" 11 | 12 | void swap(char *a, char *b) { 13 | char tmp = *a; *a = *b; *b = tmp; 14 | } 15 | 16 | char *reverseVowels(char *s) { 17 | const char *vowels = "aeiouAEIOU"; 18 | 19 | char *p1 = s, 20 | *p2 = s+strlen(s)- 1; 21 | 22 | while (p1 < p2) { 23 | if (!strchr(vowels, *p1)) { 24 | p1++; continue; 25 | } 26 | if (!strchr(vowels, *p2)) { 27 | p2--; continue; 28 | } 29 | swap(p1++, p2--); 30 | } 31 | 32 | return s; 33 | } 34 | 35 | void test(const char *expect, char *str) { 36 | int sz = strlen(str); 37 | char *s = malloc(sz + 1); 38 | strncpy(s, str, sz + 1); 39 | s = reverseVowels(s); 40 | 41 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, s); 42 | } 43 | 44 | int main(void) { 45 | test("holle", "hello"); 46 | test("leotcede", "leetcode"); 47 | test(".", "."); 48 | test("Aa", "aA"); 49 | 50 | return testOutput(); 51 | } 52 | -------------------------------------------------------------------------------- /c/000-099/08-string-to-integer-atoi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | 5 | * 需要考虑几个问题: 6 | * 1. 字符串最前面的空格 7 | * 2. 正, 负号 8 | * 3. 遇到非数字的时候终止 9 | * 4. 整型溢出时, 取 MAX/MIN 10 | */ 11 | 12 | #include /* isdigit() */ 13 | #include /* INT_MAX, INT_MIN */ 14 | #include "c/test.h" 15 | 16 | int myAtoi(char *str) { 17 | char *p = str; 18 | while (*p == ' ') p++; /* 处理之前的空格 */ 19 | 20 | int sign = 1; 21 | if (*p == '+' || *p == '-') { 22 | sign = 1 - (*p++ - '+'); 23 | } 24 | 25 | int rt = 0; 26 | while (isdigit(*p)) { 27 | if (rt > INT_MAX / 10 || 28 | (rt == INT_MAX / 10 && *p > '7')) { 29 | return sign == 1 ? INT_MAX : INT_MIN; 30 | } 31 | rt = rt * 10 + *p++ - '0'; 32 | } 33 | return rt * sign; 34 | } 35 | 36 | void test(int expect, char *str) { 37 | EXPECT_EQ_INT(expect, myAtoi(str)); 38 | } 39 | 40 | int main(void) { 41 | test(123, " +123"); 42 | test(-123, " -123"); 43 | test(1, " 1a123"); 44 | test(INT_MAX, "9999999999999999999999999"); 45 | test(INT_MIN, "-9999999999999999999999999"); 46 | 47 | return testOutput(); 48 | } 49 | -------------------------------------------------------------------------------- /c/000-099/98-validate-binary-search-tree.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 按顺序访问节点, 每个节点均大于前一个节点即为有效 6 | */ 7 | 8 | #include 9 | #include "c/data-structures/binary-tree.h" 10 | #include "c/test.h" 11 | 12 | bool isValid(struct TreeNode *node, struct TreeNode **prev) { 13 | if (node == NULL) return true; 14 | if (!isValid(node->left, prev)) return false; 15 | if (*prev != NULL && (*prev)->val >= node->val) return false; 16 | *prev = node; 17 | return isValid(node->right, prev); 18 | } 19 | 20 | bool isValidBST(struct TreeNode *root) { 21 | struct TreeNode *prev = NULL; 22 | return isValid(root, &prev); 23 | } 24 | 25 | void test(bool expect, const char *str) { 26 | struct TreeNode *root = treeParse(str); 27 | EXPECT_EQ_INT(expect, isValidBST(root)); 28 | treeFree(root); 29 | } 30 | 31 | int main(void) { 32 | test(true, "[2,1,3]"); 33 | test(false, "[5,1,4,null,null,3,6]"); 34 | 35 | test(false, "[10,5,15,null,null,6,20]"); 36 | test(true, "[2147483647]"); 37 | test(true, "[-2147483648,null,2147483647]"); 38 | test(false, "[1,2]"); 39 | 40 | return testOutput(); 41 | } 42 | -------------------------------------------------------------------------------- /c/100-199/141-linked-list-cycle.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 如果快慢指针最后相遇, 则是循环链表 6 | */ 7 | 8 | #include 9 | #include "c/data-structures/linked-list.h" 10 | #include "c/test.h" 11 | 12 | bool hasCycle(struct ListNode *head) { 13 | struct ListNode *fast = head, *slow = head; 14 | while (fast != NULL && fast->next != NULL && slow != NULL) { 15 | if ((fast = fast->next->next) == (slow = slow->next)) { 16 | return true; 17 | } 18 | } 19 | return false; 20 | } 21 | 22 | void test(bool expect, char *str, int pos) { 23 | struct ListNode *head = linkedlistParse(str); 24 | /* 构建循环链表, 之后解除 */ 25 | struct ListNode *tail = head; 26 | while (tail->next) 27 | tail = tail->next; 28 | 29 | if (pos >= 0) { 30 | tail->next = head; 31 | for (int i = 0; i < pos; i++) 32 | tail->next = tail->next->next; 33 | } 34 | 35 | EXPECT_EQ_INT(expect, hasCycle(head)); 36 | 37 | tail->next = NULL; 38 | linkedlistFree(head); 39 | } 40 | 41 | int main(void) { 42 | test(true, "[3,2,0,-4]", 1); 43 | test(true, "[1,2]", 0); 44 | test(false, "[1]", -1); 45 | 46 | return testOutput(); 47 | } 48 | -------------------------------------------------------------------------------- /c/000-099/21-merge-two-sorted-lists.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 新学的写法 -> 指针的指针 6 | */ 7 | 8 | #include "c/data-structures/linked-list.h" 9 | #include "c/test.h" 10 | 11 | /** 12 | * Definition for singly-linked list. 13 | * struct ListNode { 14 | * int val; 15 | * struct ListNode *next; 16 | * }; 17 | */ 18 | struct ListNode *mergeTwoLists(struct ListNode *l1, struct ListNode *l2) { 19 | struct ListNode *head = NULL, **p = &head; 20 | while (l1 && l2) { 21 | if (l1->val <= l2->val) { 22 | *p = l1; 23 | l1 = l1->next; 24 | } else { 25 | *p = l2; 26 | l2 = l2->next; 27 | } 28 | p = &((*p)->next); 29 | } 30 | 31 | *p = l1 ? l1 : l2; 32 | return head; 33 | } 34 | 35 | void test(const char *expect, const char *s1, const char *s2) { 36 | struct ListNode *list = mergeTwoLists(linkedlistParse(s1), linkedlistParse(s2)); 37 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, linkedlistToString(list)); 38 | 39 | linkedlistFree(list); 40 | } 41 | 42 | int main(void) { 43 | test("[1,2,3,4]", "[1,3]", "[2,4]"); 44 | test("[1,3]", "[1,3]", "[]"); 45 | 46 | return testOutput(); 47 | } 48 | -------------------------------------------------------------------------------- /c/1100-1199/1103-distribute-candies-to-people.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 蛮力解法 6 | */ 7 | 8 | #include /* malloc(), free() */ 9 | #include /* memset() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | /** 14 | * Note: The returned array must be malloced, assume caller calls free(). 15 | */ 16 | int *distributeCandies(int candies, int num_people, int *returnSize) { 17 | int *rtn = malloc(sizeof(int) * num_people); 18 | memset(rtn, 0, sizeof(int) * num_people); 19 | 20 | int i = 0, tmp; 21 | while (candies > 0) { 22 | tmp = i+1 < candies ? i+1 : candies; 23 | rtn[i++%num_people] += tmp; 24 | candies -= tmp; 25 | } 26 | 27 | *returnSize = num_people; 28 | return rtn; 29 | } 30 | 31 | void test(const char *expect, int candies, int num_people) { 32 | int returnSize; 33 | int *rtn = distributeCandies(candies, num_people, &returnSize); 34 | 35 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString1D(rtn, returnSize, ARRAY_INT)); 36 | } 37 | 38 | int main(void) { 39 | test("[1,2,3,1]", 7, 4); 40 | test("[5,2,3]", 10, 3); 41 | 42 | return testOutput(); 43 | } 44 | -------------------------------------------------------------------------------- /c/400-499/413-arithmetic-slices.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 只要知道最长的一段, 通过计算就可以知道这段有几个'片' 6 | * 长度 -> 数量 7 | * 3 -> 1 8 | * 4 -> 3 9 | * 5 -> 6 10 | * 6 -> 10 11 | * ... 12 | * 最后把他们累加起来 13 | */ 14 | 15 | #include "c/data-structures/array.h" 16 | #include "c/test.h" 17 | 18 | int doMath(int count) { 19 | if (count < 2) return 0; 20 | return count * (count - 1) / 2; 21 | } 22 | 23 | int numberOfArithmeticSlices(int *A, int ASize) { 24 | if (ASize < 3) return 0; 25 | 26 | int rt = 0, count = 1; 27 | int flag = A[1] - A[0]; 28 | for (int i = 2; i != ASize; i++) { 29 | int tmp = A[i] - A[i-1]; 30 | if (tmp == flag) { 31 | ++count; 32 | } else { 33 | rt += doMath(count); 34 | flag = tmp; 35 | count = 1; 36 | } 37 | } 38 | return rt + doMath(count); 39 | } 40 | 41 | void test(int expect, const char *str) { 42 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 43 | 44 | EXPECT_EQ_INT(expect, numberOfArithmeticSlices(arrayValue(e), arraySize(e))); 45 | 46 | arrayFree(e); 47 | } 48 | 49 | int main(void) { 50 | test(3, "[1,2,3,4]"); 51 | 52 | return testOutput(); 53 | } 54 | -------------------------------------------------------------------------------- /c/500-599/525-contiguous-array.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 把0看作-1, 累加数组内的值, 然后以累加值为Key, 数组下标为Value, 保存起来. 6 | * 每次遇到已存在的Key时, 通过下标更新一下最大长度. 7 | */ 8 | 9 | #include /* malloc(), free() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | int findMaxLength(int *nums, int numsSize) { 14 | int n = 2 * numsSize + 1; 15 | int *indexes = malloc(sizeof(int) * n); 16 | for (int i = 0; i < n; i++) 17 | indexes[i] = -2; 18 | indexes[numsSize] = -1; 19 | 20 | int max = 0, sum = 0; 21 | for (int i = 0; i < numsSize; i++) { 22 | sum += nums[i] == 0 ? -1 : 1; 23 | int *p = &indexes[sum+numsSize]; 24 | if (*p == -2) 25 | *p = i; 26 | else if (i - *p > max) 27 | max = i - *p; 28 | } 29 | free(indexes); 30 | return max; 31 | } 32 | 33 | void test(int expect, char *s) { 34 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 35 | EXPECT_EQ_INT(expect, findMaxLength(arrayValue(e), arraySize(e))); 36 | arrayFree(e); 37 | } 38 | 39 | int main(void) { 40 | test(2, "[0,1]"); 41 | test(2, "[0,1,0]"); 42 | 43 | test(6, "[0,0,1,0,0,0,1,1]"); 44 | 45 | return testOutput(); 46 | } 47 | -------------------------------------------------------------------------------- /c/000-099/14-longest-common-prefix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 排除特殊情况后, 竖向对比, 以第一个为基准 6 | */ 7 | 8 | #include /* malloc() */ 9 | #include /* strlen(), strncpy() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | char *longestCommonPrefix(char **strs, int strsSize) { 14 | int i = 0; 15 | 16 | if (strsSize > 0) { 17 | int j, len = strlen(strs[0]); /* 取第一个的长度为基准 */ 18 | for (; i < len; i++) { 19 | for (j = 1; j < strsSize; j++) { 20 | if (strs[0][i] != strs[j][i]) { 21 | goto END; 22 | } 23 | } 24 | } 25 | } 26 | END: {} 27 | char *rt = malloc(sizeof(char) * (i + 1)); 28 | if (i > 0) strncpy(rt, strs[0], i); 29 | rt[i] = '\0'; 30 | return rt; 31 | } 32 | 33 | void test(const char* expect, const char* str) { 34 | arrayEntry *e = arrayParse1D(str, ARRAY_STRING); 35 | 36 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, longestCommonPrefix(arrayValue(e), arraySize(e))); 37 | 38 | arrayFree(e); 39 | } 40 | 41 | int main(void) { 42 | test("", "[]"); 43 | 44 | test("a", "[a]"); 45 | test("a", "[a, ac]"); 46 | 47 | return testOutput(); 48 | } 49 | -------------------------------------------------------------------------------- /c/000-099/64-minimum-path-sum.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 简单的 DP 问题. 6 | * ps: 通过提交得知, 如果只有方法内用到的变量, 不需要动态创建, 会耗时. 7 | */ 8 | 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | int minPathSum(int **grid, int gridSize, int *gridColSize) { 13 | int row = gridSize, col = *gridColSize, i, j; 14 | int dp[row][col]; 15 | 16 | /* 初始化边界 */ 17 | dp[0][0] = grid[0][0]; 18 | for (i = 1; i < row; ++i) 19 | dp[i][0] = grid[i][0] + dp[i - 1][0]; 20 | for (j = 1; j < col; ++j) 21 | dp[0][j] = grid[0][j] + dp[0][j - 1]; 22 | 23 | for (i = 1; i < row; ++i) 24 | for (j = 1; j < col; ++j) 25 | dp[i][j] = grid[i][j] + (dp[i - 1][j] <= dp[i][j - 1] ? dp[i - 1][j] : dp[i][j - 1]); 26 | 27 | return dp[row - 1][col - 1]; 28 | } 29 | 30 | void test(int expect, const char *s) { 31 | arrayEntry *e = arrayParse2D(s, ARRAY_INT); 32 | 33 | EXPECT_EQ_INT(expect, minPathSum(arrayValue(e), arrayRow(e), arrayCols(e))); 34 | 35 | arrayFree(e); 36 | } 37 | 38 | int main(void) { 39 | test(7, 40 | "[" 41 | "[1,3,1]," 42 | "[1,5,1]," 43 | "[4,2,1]" 44 | "]"); 45 | 46 | return testOutput(); 47 | } 48 | -------------------------------------------------------------------------------- /c/100-199/108-convert-sorted-array-to-binary-search-tree.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 有序数组 转成 二叉搜索树? 用递归 6 | */ 7 | 8 | #include /* malloc() */ 9 | #include "c/data-structures/array.h" 10 | #include "c/data-structures/binary-tree.h" 11 | #include "c/test.h" 12 | 13 | struct TreeNode *toBST(int *nums, int p, int q) { 14 | if (p >= q) return NULL; 15 | 16 | int mid = (p + q) / 2; 17 | struct TreeNode *node = malloc(sizeof(struct TreeNode)); 18 | node->val = nums[mid]; 19 | node->left = toBST(nums, p, mid); 20 | node->right = toBST(nums, mid+1, q); 21 | return node; 22 | } 23 | 24 | struct TreeNode *sortedArrayToBST(int *nums, int numsSize) { 25 | return toBST(nums, 0, numsSize); 26 | } 27 | 28 | void test(const char *expect, const char *nums) { 29 | arrayEntry *e = arrayParse1D(nums, ARRAY_INT); 30 | struct TreeNode *t = sortedArrayToBST(arrayValue(e), arraySize(e)); 31 | 32 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, treeToString(t)); 33 | 34 | arrayFree(e); 35 | treeFree(t); 36 | } 37 | 38 | int main(void) { 39 | test("[0,-3,9,-10,null,5]", "[-10,-3,0,5,9]"); 40 | test("[3,1]", "[1,3]"); 41 | 42 | return testOutput(); 43 | } 44 | -------------------------------------------------------------------------------- /c/000-099/83-remove-duplicates-from-sorted-list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 经过了 21 和 24 之后, 算是学会了 'pointer-pointer' 的写法 6 | */ 7 | 8 | #include /* free() */ 9 | #include "c/data-structures/linked-list.h" 10 | #include "c/test.h" 11 | 12 | /** 13 | * Definition for singly-linked list. 14 | * struct ListNode { 15 | * int val; 16 | * struct ListNode *next; 17 | * }; 18 | */ 19 | struct ListNode *deleteDuplicates(struct ListNode *head) { 20 | struct ListNode **p = &head, *a, *b; 21 | while ((a = *p)) { 22 | while ((b = a->next) && a->val == b->val) { 23 | a->next = b->next; 24 | free(b); 25 | } 26 | p = &((*p)->next); 27 | } 28 | return head; 29 | } 30 | 31 | void test(const char *expect, const char *s) { 32 | struct ListNode* list = deleteDuplicates(linkedlistParse(s)); 33 | 34 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, linkedlistToString(list)); 35 | 36 | linkedlistFree(list); 37 | } 38 | 39 | /* 40 | Given 1->1->2, return 1->2. 41 | Given 1->1->2->3->3, return 1->2->3. 42 | */ 43 | int main(void) { 44 | test("[1,2]", "[1,1,2]"); 45 | test("[1,2,3]", "[1,1,2,3,3]"); 46 | 47 | return testOutput(); 48 | } 49 | -------------------------------------------------------------------------------- /c/000-099/48-rotate-image.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 画圆 6 | */ 7 | 8 | #include "c/data-structures/array.h" 9 | #include "c/test.h" 10 | 11 | void rotate(int **matrix, int matrixRowSize, int matrixColSize) { 12 | int tmp; 13 | for (int i = 0; i < matrixRowSize / 2; ++i) { 14 | for (int j = i; j < matrixRowSize-1-i; ++j) { 15 | tmp = matrix[i][j]; 16 | matrix[i][j] = matrix[matrixRowSize-1-j][i]; 17 | matrix[matrixRowSize-1-j][i] = matrix[matrixRowSize-1-i][matrixRowSize-1-j]; 18 | matrix[matrixRowSize-1-i][matrixRowSize-1-j] = matrix[j][matrixRowSize-1-i]; 19 | matrix[j][matrixRowSize-1-i] = tmp; 20 | } 21 | } 22 | } 23 | 24 | void test(const char *expect, const char *str) { 25 | arrayEntry *e = arrayParse2D(str, ARRAY_INT); 26 | rotate(arrayValue(e), arrayRow(e), arrayCol(e)); 27 | 28 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString(e)); 29 | 30 | arrayFree(e); 31 | } 32 | 33 | int main(void) { 34 | test("[[7,4,1],[8,5,2],[9,6,3]]", 35 | "[[1,2,3],[4,5,6],[7,8,9]]"); 36 | test("[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]", 37 | "[[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]"); 38 | 39 | return testOutput(); 40 | } 41 | -------------------------------------------------------------------------------- /c/000-099/01-two-sum.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 暴力计算, 两层循环 6 | */ 7 | 8 | #include /* malloc(), free() */ 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | /** 13 | * Note: The returned array must be malloced, assume caller calls free(). 14 | */ 15 | int* twoSum(int *nums, int numsSize, int target) { 16 | int i, j; 17 | for (i = 0; i != numsSize - 1; ++i) { 18 | for (j = i + 1; j != numsSize; ++j) { 19 | if (nums[i] + nums[j] == target) { 20 | int *r = malloc(sizeof(int) * 2); 21 | r[0] = i; 22 | r[1] = j; 23 | return r; 24 | } 25 | } 26 | } 27 | return NULL; 28 | } 29 | 30 | void test(const char *str, int target) { 31 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 32 | int *nums = arrayValue(e); 33 | int *answer = twoSum(nums, arraySize(e), target); 34 | 35 | EXPECT_EQ_INT(target, nums[answer[0]] + nums[answer[1]]); 36 | 37 | free(answer); 38 | arrayFree(e); 39 | } 40 | 41 | /* 42 | Given nums = [2, 7, 11, 15], target = 9, 43 | 44 | Because nums[0] + nums[1] = 2 + 7 = 9, 45 | return [0, 1]. 46 | */ 47 | int main(void) { 48 | test("[2, 7, 11, 15]", 9); 49 | 50 | return testOutput(); 51 | } 52 | -------------------------------------------------------------------------------- /c/000-099/41-first-missing-positive.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 利用原数组的空间, 下标从1开始, 往里填数. 6 | * 最后找到第一个不正确的值. 7 | */ 8 | 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | int firstMissingPositive(int *nums, int numsSize) { 13 | if (numsSize == 0) return 1; 14 | 15 | int i = 0; 16 | while (i < numsSize) { 17 | /* 负数 超出范围 正确值 重复的正确值 */ 18 | if (nums[i] <= 0 || nums[i] >= numsSize || nums[i] == i + 1 || nums[i] == nums[nums[i] - 1]) { 19 | i++; 20 | } else { 21 | int tmp = nums[nums[i] - 1]; 22 | nums[nums[i] - 1] = nums[i]; 23 | nums[i] = tmp; 24 | } 25 | } 26 | 27 | i = 0; 28 | while (i < numsSize && nums[i] == i + 1) i++; 29 | 30 | return i + 1; 31 | } 32 | 33 | void test(int expect, char *s) { 34 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 35 | 36 | EXPECT_EQ_INT(expect, firstMissingPositive(arrayValue(e), arraySize(e))); 37 | 38 | arrayFree(e); 39 | } 40 | 41 | int main(void) { 42 | test(3, "[1,2,0]"); 43 | test(2, "[3,4,-1,1]"); 44 | test(1, "[7,8,9,11,12]"); 45 | 46 | test(1, "[]"); 47 | test(2, "[1]"); 48 | test(2, "[1,1]"); 49 | 50 | return testOutput(); 51 | } 52 | -------------------------------------------------------------------------------- /c/200-299/297-serialize-and-deserialize-binary-tree.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/data-structures/binary-tree.h" 7 | #include "c/test.h" 8 | 9 | /** 10 | * Definition for a binary tree node. 11 | * struct TreeNode { 12 | * int val; 13 | * struct TreeNode *left; 14 | * struct TreeNode *right; 15 | * }; 16 | */ 17 | /** Encodes a tree to a single string. */ 18 | char *serialize(struct TreeNode *root) { 19 | return treeToString(root); 20 | } 21 | 22 | /** Decodes your encoded data to tree. */ 23 | struct TreeNode *deserialize(char *data) { 24 | return treeParse(data); 25 | } 26 | 27 | // Your functions will be called as such: 28 | // char* data = serialize(root); 29 | // deserialize(data); 30 | 31 | void test(char *data) { 32 | struct TreeNode *root = deserialize(data); 33 | char *actual = serialize(root); 34 | 35 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(data, actual); 36 | 37 | treeFree(root); 38 | } 39 | 40 | int main(void) { 41 | test("[1,2,3,null,null,4,5]"); 42 | 43 | // https://leetcode.com/faq/#binary-tree 44 | test("[]"); 45 | test("[1,2,3]"); 46 | test("[1,null,2,3]"); 47 | test("[5,4,7,3,null,2,null,-1,null,9]"); 48 | 49 | return testOutput(); 50 | } 51 | -------------------------------------------------------------------------------- /c/1000-1099/1008-construct-binary-search-tree-from-preorder-traversal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 递归解法. 6 | * 找到第一个大于根结点的值, 前一半为左树, 右有一半为右树. 7 | */ 8 | 9 | #include 10 | #include "c/data-structures/array.h" 11 | #include "c/data-structures/binary-tree.h" 12 | #include "c/test.h" 13 | 14 | struct TreeNode *recursive(int *preorder, int i, int j) { 15 | if (i > j) return NULL; 16 | struct TreeNode *root = treeNewNode(preorder[i]); 17 | int mid = i; 18 | for (; mid <= j; mid++) 19 | if (preorder[mid] > root->val) 20 | break; 21 | root->left = recursive(preorder, i + 1, mid - 1); 22 | root->right = recursive(preorder, mid, j); 23 | return root; 24 | } 25 | 26 | struct TreeNode *bstFromPreorder(int *preorder, int preorderSize) { 27 | return recursive(preorder, 0, preorderSize - 1); 28 | } 29 | 30 | void test(const char *expect, char *s) { 31 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 32 | struct TreeNode *root = bstFromPreorder(arrayValue(e), arraySize(e)); 33 | 34 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, treeToString(root)); 35 | 36 | treeFree(root); 37 | arrayFree(e); 38 | } 39 | 40 | int main(void) { 41 | test("[8,5,10,1,7,null,12]", "[8,5,1,7,10,12]"); 42 | 43 | return testOutput(); 44 | } 45 | -------------------------------------------------------------------------------- /c/200-299/221-maximal-square.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) 2017, Saul Lawliet 4 | * All rights reserved. 5 | * 6 | * 动态规划,取3方向 7 | */ 8 | 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | #define MIN(a, b) ((a) <= (b) ? (a) : (b)) 13 | #define MAX(a, b) ((a) >= (b) ? (a) : (b)) 14 | int maximalSquare(char **matrix, int matrixSize, int *matrixColSize) { 15 | int rtn = '0'; 16 | for (int i = 0; i < matrixSize; ++i) { 17 | for (int j = 0; j < matrixColSize[0]; ++j) { 18 | if (matrix[i][j] != '0') { 19 | if (i > 0 && j > 0) 20 | matrix[i][j] = MIN(MIN(matrix[i-1][j], matrix[i][j-1]), matrix[i-1][j-1]) + 1; 21 | rtn = MAX(rtn, matrix[i][j]); 22 | } 23 | } 24 | } 25 | 26 | rtn -= '0'; 27 | return rtn * rtn; 28 | } 29 | 30 | void test(int expect, const char *str) { 31 | arrayEntry *e = arrayParse2D(str, ARRAY_CHAR); 32 | 33 | EXPECT_EQ_INT(expect, maximalSquare(arrayValue(e), arrayRow(e), arrayCols(e))); 34 | 35 | arrayFree(e); 36 | } 37 | 38 | int main(void) { 39 | test(4, "[[1, 0, 1, 0, 0], \ 40 | [1, 0, 1, 1, 1], \ 41 | [1, 1, 1, 1, 1], \ 42 | [1, 0, 0, 1, 0]]"); 43 | test(0, "[]"); 44 | test(1, "[[1]]"); 45 | test(4, "[[1,0,1,0],[1,0,1,1],[1,0,1,1],[1,1,1,1]]"); 46 | 47 | return testOutput(); 48 | } 49 | -------------------------------------------------------------------------------- /c/400-499/412-fizz-buzz.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 使用 snprintf 替代 itoa 5 | */ 6 | 7 | #include /* snprintf() */ 8 | #include /* malloc(), free() */ 9 | #include /* memcpy() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | /** 14 | * Return an array of size *returnSize. 15 | * Note: The returned array must be malloced, assume caller calls free(). 16 | */ 17 | char **fizzBuzz(int n, int *returnSize) { 18 | *returnSize = n; 19 | char **rtn = malloc(sizeof(char*) * n); 20 | for (int i = 1; i <= n; i++) { /* sizeof(char) == 1 */ 21 | if (i % 15 == 0) memcpy(rtn[i-1] = malloc(9), "FizzBuzz", 9); 22 | else if (i % 3 == 0) memcpy(rtn[i-1] = malloc(5), "Fizz", 5); 23 | else if (i % 5 == 0) memcpy(rtn[i-1] = malloc(5), "Buzz", 5); 24 | else snprintf(rtn[i-1] = malloc(i/10+2), i/10+2, "%d", i); 25 | } 26 | return rtn; 27 | } 28 | 29 | void test(const char *expect, int n) { 30 | int returnSize; 31 | char **a = fizzBuzz(n, &returnSize); 32 | 33 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString1D(a, returnSize, ARRAY_STRING)); 34 | } 35 | 36 | int main(void) { 37 | test("[1,2,Fizz,4,Buzz,Fizz,7,8,Fizz,Buzz,11,Fizz,13,14,FizzBuzz,16]", 16); 38 | 39 | return testOutput(); 40 | } 41 | -------------------------------------------------------------------------------- /c/000-099/63-unique-paths-ii.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 相比较'62', 这里增加了障碍物, 只要设置障碍物的点为0, 其他规则照旧 6 | */ 7 | 8 | #include "c/data-structures/array.h" 9 | #include "c/test.h" 10 | 11 | int uniquePathsWithObstacles(int **obstacleGrid, int obstacleGridRowSize, int obstacleGridColSize) { 12 | // m n 13 | int grid[100][100]; /* 题目已说上限, 就不动态创建了 */ 14 | if (obstacleGrid[0][0] == 1) return 0; 15 | grid[0][0] = 1; 16 | 17 | int i, j; 18 | for (i = 1; i < obstacleGridRowSize; i++) 19 | grid[i][0] = obstacleGrid[i][0] == 0 ? grid[i-1][0] : 0; 20 | 21 | for (i = 1; i < obstacleGridColSize; i++) 22 | grid[0][i] = obstacleGrid[0][i] == 0 ? grid[0][i-1] : 0; 23 | 24 | for (i = 1; i < obstacleGridRowSize; i++) 25 | for (j = 1; j < obstacleGridColSize; j++) 26 | grid[i][j] = obstacleGrid[i][j] == 0 ? grid[i-1][j] + grid[i][j-1] : 0; 27 | 28 | return grid[obstacleGridRowSize-1][obstacleGridColSize-1]; 29 | } 30 | 31 | void test(int expect, const char *str) { 32 | arrayEntry *e = arrayParse2D(str, ARRAY_INT); 33 | 34 | EXPECT_EQ_INT(expect, uniquePathsWithObstacles(arrayValue(e), arrayRow(e), arrayCol(e))); 35 | 36 | arrayFree(e); 37 | } 38 | 39 | int main(void) { 40 | test(2, "[[0, 0, 0], [0, 1, 0], [0, 0, 0]]"); 41 | 42 | return testOutput(); 43 | } 44 | -------------------------------------------------------------------------------- /c/200-299/238-product-of-array-except-self.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 题目已经给了很多提示: 禁止用除法、时间复杂度O(n)、空间复杂度O(1)、前缀/后缀. 6 | * 7 | * 把提示组合起来, 就是从前遍历一遍算一下乘积, 存到新的数组中. 8 | * 再从后向前遍历一下, 计算乘积继续保存到数组中. 9 | */ 10 | 11 | #include /* malloc() */ 12 | #include "c/data-structures/array.h" 13 | #include "c/test.h" 14 | 15 | /** 16 | * Note: The returned array must be malloced, assume caller calls free(). 17 | */ 18 | int *productExceptSelf(int *nums, int numsSize, int *returnSize) { 19 | *returnSize = numsSize; 20 | if (numsSize == 0) { 21 | return NULL; 22 | } 23 | 24 | int *rtn = malloc(sizeof(int) * numsSize); 25 | rtn[0] = 1; 26 | for (int i = 1; i < numsSize; i++) { 27 | rtn[i] = rtn[i-1] * nums[i-1]; 28 | } 29 | 30 | int r = 1; 31 | for (int i = numsSize-1; i > 0; i--) { 32 | r *= nums[i]; 33 | rtn[i-1] *= r; 34 | } 35 | 36 | return rtn; 37 | } 38 | 39 | void test(const char *expect, char *s) { 40 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 41 | int returnSize; 42 | int *rtn = productExceptSelf(arrayValue(e), arraySize(e), &returnSize); 43 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString1D(rtn, returnSize, ARRAY_INT)); 44 | arrayFree(e); 45 | } 46 | 47 | int main(void) { 48 | test("[24,12,8,6]", "[1,2,3,4]"); 49 | 50 | return testOutput(); 51 | } 52 | -------------------------------------------------------------------------------- /c/000-099/13-roman-to-integer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 罗马数字含义: 6 | * I, V, X, L, C, D, M 7 | * 1, 5, 10, 50, 100, 500, 1000 8 | * 9 | * 正常情况都是累加, 以下情况除外: 10 | * IV, IX -- 4, 9 11 | * XL, XC -- 40, 90 12 | * CD, CM -- 400, 900 13 | */ 14 | 15 | #include "c/test.h" 16 | 17 | int romanToInt(char *s) { 18 | int rt = 0; 19 | char *p = s; 20 | while (*p) { 21 | switch (*p++) { 22 | /* 此时 *p 已经后移了 */ 23 | case 'I': 24 | if (*p != '\0' && (*p == 'V' || *p == 'X')) 25 | rt -= 1; 26 | else 27 | rt += 1; 28 | break; 29 | case 'X': 30 | if (*p != '\0' && (*p == 'L' || *p == 'C')) 31 | rt -= 10; 32 | else 33 | rt += 10; 34 | break; 35 | case 'C': 36 | if (*p != '\0' && (*p == 'D' || *p == 'M')) 37 | rt -= 100; 38 | else 39 | rt += 100; 40 | break; 41 | case 'V': rt += 5; break; 42 | case 'L': rt += 50; break; 43 | case 'D': rt += 500; break; 44 | case 'M': rt += 1000; break; 45 | } 46 | } 47 | return rt; 48 | } 49 | 50 | void test(int expect, char *s) { 51 | EXPECT_EQ_INT(expect, romanToInt(s)); 52 | } 53 | 54 | int main(void) { 55 | test(1, "I"); 56 | test(4, "IV"); 57 | test(40, "XL"); 58 | 59 | return testOutput(); 60 | } 61 | -------------------------------------------------------------------------------- /c/300-399/338-counting-bits.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * Follow up: 6 | * - It is very easy to come up with a solution with a runtime of O(n log n). Can you do it in linear time O(n) and possibly in a single pass? 7 | * 8 | * 如果是 O(n) 的时间复杂度, 那么思考方向应该类似于动态规划的做法 9 | * PS: 尝试引入变量, 来减少循环中的计算, 但效果不明显, 可能原因是: 相同的代码每次执行的时候可能会有不同的运行时间 10 | */ 11 | 12 | #include "c/data-structures/array.h" 13 | #include "c/test.h" 14 | 15 | /** 16 | * Note: The returned array must be malloced, assume caller calls free(). 17 | */ 18 | int *countBits(int n, int *returnSize) { 19 | *returnSize = n + 1; 20 | int *returnArray = malloc(sizeof(int) * *returnSize); 21 | returnArray[0] = 0; 22 | if (n >= 1) returnArray[1] = 1; 23 | int pow = 4; 24 | for (int i = 2; i < *returnSize; i++) { 25 | if (i < pow) { 26 | returnArray[i] = 1 + returnArray[i - pow / 2]; 27 | } else { 28 | returnArray[i] = 1; 29 | pow <<= 1; 30 | } 31 | } 32 | return returnArray; 33 | } 34 | 35 | void test(const char *expect, int n) { 36 | int returnSize; 37 | int *returnArray = countBits(n, &returnSize); 38 | 39 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString1D(returnArray, returnSize, ARRAY_INT)); 40 | } 41 | 42 | int main(void) { 43 | test("[0,1,1]", 2); 44 | test("[0,1,1,2,1,2]", 5); 45 | 46 | return testOutput(); 47 | } 48 | -------------------------------------------------------------------------------- /c/algorithms/sort-test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/algorithms/sort.h" 7 | #include /* malloc() */ 8 | #include /* memcpy() */ 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | typedef enum SORT_TYPE { 13 | INSERTION, MERGE, QUICK 14 | } SortType; 15 | 16 | void test(SortType type, int* expect, int* actual, int size) { 17 | switch (type) { 18 | case INSERTION: 19 | sortInsertion(actual, size); 20 | break; 21 | case MERGE: 22 | sortMerge(actual, size); 23 | break; 24 | case QUICK: 25 | sortQuick(actual, size); 26 | break; 27 | } 28 | 29 | EXPECT_EQ_STRING_AND_FREE(arrayToString1D(expect, size, ARRAY_INT), 30 | arrayToString1D(actual, size, ARRAY_INT)); 31 | } 32 | 33 | int* copy(int a[], int size) { 34 | int *rt = malloc(sizeof(int) * size); 35 | memcpy(rt, a, sizeof(int) * size); 36 | return rt; 37 | } 38 | 39 | int main(void) { 40 | int size = 6; 41 | int actual[] = {34, 8, 64, 51, 32, 21}; 42 | int expect[] = {8, 21, 32, 34, 51, 64}; 43 | 44 | test(INSERTION, copy(expect, size), copy(actual, size), size); 45 | test(MERGE, copy(expect, size), copy(actual, size), size); 46 | test(QUICK, copy(expect, size), copy(actual, size), size); 47 | 48 | return testOutput(); 49 | } 50 | -------------------------------------------------------------------------------- /c/1100-1199/1138-alphabet-board-path.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 最短的路线有多种走法, 为了统一, 我们这里默认是先上下后左右 6 | * 注意: 有个例外是移动到'z'时, 先左后下 7 | */ 8 | 9 | #include /* malloc() */ 10 | #include /* strlen() */ 11 | #include "c/test.h" 12 | 13 | char *alphabetBoardPath(char *target) { 14 | // 最长的步数是 'z' -> 'e', 共9步, 加上'!', 一共10个 15 | size_t len = strlen(target); 16 | char *path = malloc(sizeof(char) * (10 * len + 1)); 17 | char *p = path; 18 | int x1 = 0, y1 = 0, x2, y2, v; 19 | for (size_t i = 0; i < len; i++) { 20 | v = target[i] - 'a'; 21 | x2 = v / 5, y2 = v % 5; 22 | 23 | if (target[i] == 'z') { 24 | // 先左后下 25 | while (y2 < y1) { y1--; *p++ = 'L'; } 26 | while (x2 > x1) { x1++; *p++ = 'D'; } 27 | } else { 28 | // 先上下后左右 29 | while (x2 > x1) { x1++; *p++ = 'D'; } 30 | while (x2 < x1) { x1--; *p++ = 'U'; } 31 | while (y2 > y1) { y1++; *p++ = 'R'; } 32 | while (y2 < y1) { y1--; *p++ = 'L'; } 33 | } 34 | 35 | *p++ = '!'; 36 | } 37 | *p++ = '\0'; 38 | return path; 39 | } 40 | 41 | void test(const char *expect, char *target) { 42 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, alphabetBoardPath(target)); 43 | } 44 | 45 | int main(void) { 46 | test("DDR!UURRR!!DDD!", "leet"); 47 | test("RR!DDRR!UUL!R!", "code"); 48 | 49 | return testOutput(); 50 | } 51 | -------------------------------------------------------------------------------- /c/000/perform-string-shifts.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 简单的问题, 描述的这么复杂, 实际就是偏移字符串 6 | * 需要考虑的是超出字符串的部分需要取余 7 | */ 8 | 9 | #include /* strlen() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | char *stringShift(char *s, int **shift, int shiftSize, int *shiftColSize) { 14 | int len = strlen(s); 15 | char *rtn = malloc(sizeof(char) * (len + 1)); 16 | rtn[len] = '\0'; 17 | 18 | int move = 0; 19 | for (int i = 0; i < shiftSize; i++) 20 | move += (shift[i][0] > 0 ? 1 : -1) * shift[i][1]; 21 | 22 | /* 当 move 为负数时, 需要处理一下 */ 23 | move %= len; 24 | if (move < 0) move += len; 25 | 26 | for (int i = 0; i < len; i++) 27 | rtn[(i + move) % len] = s[i]; 28 | 29 | return rtn; 30 | } 31 | 32 | void test(const char *expect, char *s, char *shift) { 33 | arrayEntry *e = arrayParse2D(shift, ARRAY_INT); 34 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, stringShift(s, arrayValue(e), arrayRow(e), arrayCols(e))); 35 | arrayFree(e); 36 | } 37 | 38 | int main(void) { 39 | test("cab", "abc", "[[0,1],[1,2]]"); 40 | test("efgabcd", "abcdefg", "[[1,1],[1,1],[0,2],[1,3]]"); 41 | 42 | test("hcjwpdh", "wpdhhcj", "[[0,7],[1,7],[1,0],[1,3],[0,3],[0,6],[1,2]]"); 43 | test("qpifxqgwki", "xqgwkiqpif", "[[1,4],[0,7],[0,8],[0,7],[0,6],[1,3],[0,1],[1,7],[0,5],[0,6]]"); 44 | 45 | return testOutput(); 46 | } 47 | -------------------------------------------------------------------------------- /c/000-099/61-rotate-list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 第一次提交的时候, 以为 k > 0 && k < len(head) 6 | * 实际上, k 可以是任意的正整数 7 | */ 8 | 9 | #include "c/data-structures/linked-list.h" 10 | #include "c/test.h" 11 | 12 | /** 13 | * Definition for singly-linked list. 14 | * struct ListNode { 15 | * int val; 16 | * struct ListNode *next; 17 | * }; 18 | */ 19 | struct ListNode *rotateRight(struct ListNode *head, int k) { 20 | if (!k || !head) return head; 21 | struct ListNode *b = head; 22 | int i = k; 23 | 24 | while (i) { 25 | if (!b) { 26 | i %= (k-i); /* 优化 k 远大于 len(head) 的情况 */ 27 | if (!i) break; 28 | b = head; 29 | } 30 | b = b->next; 31 | i--; 32 | } 33 | if (!b) return head; 34 | 35 | struct ListNode *a = head, *rt; 36 | while (b->next) { 37 | a = a->next; 38 | b = b->next; 39 | } 40 | rt = a->next; 41 | a->next = NULL; 42 | b->next = head; 43 | return rt; 44 | } 45 | 46 | void test(const char *expect, const char *s, int k) { 47 | struct ListNode *list = rotateRight(linkedlistParse(s), k); 48 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, linkedlistToString(list)); 49 | 50 | linkedlistFree(list); 51 | } 52 | 53 | int main(void) { 54 | test("[4,5,1,2,3]", "[1,2,3,4,5]", 2); 55 | test("[4,5,1,2,3]", "[1,2,3,4,5]", 12); 56 | test("[2,3,4,5,1]", "[1,2,3,4,5]", 4); 57 | 58 | return testOutput(); 59 | } 60 | -------------------------------------------------------------------------------- /c/100-199/109-convert-sorted-list-to-binary-search-tree.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 思路跟108一样: 区别在于用“快慢指针”取中间节点 6 | */ 7 | 8 | #include "c/data-structures/binary-tree.h" 9 | #include "c/data-structures/linked-list.h" 10 | #include "c/test.h" 11 | 12 | struct TreeNode *toBST(struct ListNode *head, struct ListNode *tail) { 13 | if (head == tail) return NULL; 14 | 15 | struct ListNode *slow = head; 16 | struct ListNode *fast = head; 17 | while (fast && fast != tail && fast->next && fast->next != tail) { 18 | slow = slow->next; 19 | fast = fast->next->next; 20 | } 21 | 22 | struct TreeNode *node = malloc(sizeof(struct TreeNode)); 23 | node->val = slow->val; 24 | node->left = toBST(head, slow); 25 | node->right = toBST(slow->next, tail); 26 | return node; 27 | } 28 | 29 | struct TreeNode *sortedListToBST(struct ListNode *head) { 30 | return toBST(head, NULL); 31 | } 32 | 33 | void test(const char *expect, const char *nums) { 34 | struct ListNode *list = linkedlistParse(nums); 35 | struct TreeNode *tree = sortedListToBST(list); 36 | 37 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, treeToString(tree)); 38 | 39 | treeFree(tree); 40 | linkedlistFree(list); 41 | } 42 | 43 | int main(void) { 44 | test("[0,-3,9,-10,null,5]", "[-10,-3,0,5,9]"); 45 | test("[]", "[]"); 46 | test("[4,2,6,1,3,5,7,0]", "[0,1,2,3,4,5,6,7]"); 47 | 48 | return testOutput(); 49 | } 50 | -------------------------------------------------------------------------------- /c/000-099/74-search-a-2d-matrix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * https://leetcode.com/problems/search-a-2d-matrix/ 6 | * Q: 在一个有序的二维数组中, 判断是否存在一个特定的值 7 | * 8 | * 转换一下矩阵下标, 同样是二分查找 9 | */ 10 | 11 | #include 12 | #include "c/data-structures/array.h" 13 | #include "c/test.h" 14 | 15 | bool searchMatrix(int **matrix, int matrixSize, int *matrixColSize, int target) { 16 | int a = 0, b = matrixSize * *matrixColSize - 1; 17 | while (a <= b) { 18 | int i = (a + b) / 2; 19 | int v = matrix[i / *matrixColSize][i % *matrixColSize]; 20 | if (v > target) { 21 | b = i - 1; 22 | } else if (v < target) { 23 | a = i + 1; 24 | } else { 25 | return true; 26 | } 27 | } 28 | return false; 29 | } 30 | 31 | void test(bool expect, const char *matrix, int target) { 32 | arrayEntry *e = arrayParse2D(matrix, ARRAY_INT); 33 | 34 | int col = arrayCol(e); 35 | EXPECT_EQ_INT(expect, searchMatrix(arrayValue(e), arrayRow(e), &col, target)); 36 | 37 | arrayFree(e); 38 | } 39 | 40 | int main(void) { 41 | test(true, 42 | "[" 43 | "[1, 3, 5, 7]," 44 | "[10, 11, 16, 20]," 45 | "[23, 30, 34, 50]" 46 | "]", 47 | 3); 48 | test(false, 49 | "[" 50 | "[1, 3, 5, 7]," 51 | "[10, 11, 16, 20]," 52 | "[23, 30, 34, 50]" 53 | "]", 54 | 13); 55 | 56 | return testOutput(); 57 | } 58 | -------------------------------------------------------------------------------- /c/100-199/150-evaluate-reverse-polish-notation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 后缀表达式, 维护一个存放数字的栈, 遇到数字放入, 遇到符号弹出, 即可. 6 | */ 7 | 8 | #include /* malloc(), atoi() */ 9 | 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | int evalRPN(char **tokens, int tokensSize) { 14 | int *stack = malloc(sizeof(int) * (tokensSize / 2 + 1)); 15 | int top = 0; 16 | 17 | int n, a, b; 18 | for (int i = 0; i < tokensSize; i++) { 19 | char first = tokens[i][0]; 20 | if (first == '+' || (first == '-' && !tokens[i][1]) || first == '*' || first == '/') { 21 | b = stack[--top]; 22 | a = stack[--top]; 23 | switch (first) { 24 | case '+': n = a + b; break; 25 | case '-': n = a - b; break; 26 | case '*': n = a * b; break; 27 | case '/': n = a / b; break; 28 | } 29 | } else { 30 | n = atoi(tokens[i]); 31 | } 32 | stack[top++] = n; 33 | } 34 | 35 | free(stack); 36 | 37 | return n; 38 | } 39 | 40 | 41 | void test(int expect, char *str) { 42 | arrayEntry *e = arrayParse1D(str, ARRAY_STRING); 43 | 44 | EXPECT_EQ_INT(expect, evalRPN(arrayValue(e), arraySize(e))); 45 | 46 | arrayFree(e); 47 | } 48 | 49 | int main(void) { 50 | test(9, "[2, 1, +, 3, *]"); 51 | test(6, "[4, 13, 5, /, +]"); 52 | test(22, "[10, 6, 9, 3, +, -11, *, /, *, 17, +, 5, +]"); 53 | 54 | return testOutput(); 55 | } 56 | -------------------------------------------------------------------------------- /c/300-399/393-utf-8-validation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include 7 | #include "c/data-structures/array.h" 8 | #include "c/test.h" 9 | 10 | bool validUtf8(int *data, int dataSize) { 11 | int count = 0; 12 | for (int i = 0; i < dataSize; ++i) { 13 | if (count == 0) { 14 | if (data[i] >> 7 == 0x0) count = 0; 15 | else if (data[i] >> 5 == 0x6) count = 1; 16 | else if (data[i] >> 4 == 0xE) count = 2; 17 | else if (data[i] >> 3 == 0x1E) count = 3; 18 | else return false; 19 | } else { 20 | if (data[i] >> 6 != 0x2) return false; 21 | count--; 22 | } 23 | } 24 | return count == 0; 25 | } 26 | 27 | void test(bool expect, const char *str) { 28 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 29 | 30 | EXPECT_EQ_INT(expect, validUtf8(arrayValue(e), arraySize(e))); 31 | 32 | arrayFree(e); 33 | } 34 | 35 | /* 36 | Char. number range | UTF-8 octet sequence 37 | (hexadecimal) | (binary) 38 | --------------------+--------------------------------------------- 39 | 0000 0000-0000 007F | 0xxxxxxx 40 | 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 41 | 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 42 | 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 43 | */ 44 | int main(void) { 45 | test(true, "[197, 130, 1]"); 46 | test(false, "[235, 140, 4]"); 47 | 48 | return testOutput(); 49 | } 50 | -------------------------------------------------------------------------------- /c/000-099/73-set-matrix-zeroes.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 将相关数据存到第一行, 第一列中 6 | */ 7 | 8 | #include 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | void setZeroes(int **matrix, int matrixRowSize, int matrixColSize) { 13 | bool firstRow = false, firstCol = false; 14 | for (int i = 0; i < matrixRowSize; ++i) 15 | for (int j = 0; j < matrixColSize; ++j) 16 | if (matrix[i][j] == 0) { 17 | if (i == 0) firstRow = true; 18 | if (j == 0) firstCol = true; 19 | matrix[0][j] = 0; 20 | matrix[i][0] = 0; 21 | } 22 | 23 | for (int i = 1; i < matrixRowSize; ++i) 24 | for (int j = 1; j < matrixColSize; ++j) 25 | if (matrix[i][0] == 0 || matrix[0][j] == 0) 26 | matrix[i][j] = 0; 27 | 28 | if (firstRow) { 29 | for (int j = 0; j < matrixColSize; ++j) 30 | matrix[0][j] = 0; 31 | } 32 | 33 | if (firstCol) { 34 | for (int i = 0; i < matrixRowSize; ++i) 35 | matrix[i][0] = 0; 36 | } 37 | } 38 | 39 | void test(const char *expect, const char *str) { 40 | arrayEntry *e = arrayParse2D(str, ARRAY_INT); 41 | setZeroes(arrayValue(e), arrayRow(e), arrayCol(e)); 42 | 43 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString(e)); 44 | 45 | arrayFree(e); 46 | } 47 | 48 | int main(void) { 49 | test("[[0,0,0],[0,0,0],[0,8,0]]", "[[0,2,3],[4,5,0],[7,8,9]]"); 50 | 51 | return testOutput(); 52 | } 53 | -------------------------------------------------------------------------------- /c/data-structures/linked-list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2018, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/data-structures/linked-list.h" 7 | #include /* NULL, malloc(), free() */ 8 | #include "c/data-structures/array.h" 9 | 10 | static struct ListNode *makeByIndex(arrayEntry *e, int index) { 11 | int size = arraySize(e); 12 | if (index >= size) return NULL; 13 | 14 | struct ListNode *list = malloc(sizeof(struct ListNode)); 15 | list->val = ((int *)arrayValue(e))[index]; 16 | list->next = makeByIndex(e, index + 1); 17 | return list; 18 | } 19 | 20 | struct ListNode *linkedlistParse(const char *str) { 21 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 22 | struct ListNode *list = makeByIndex(e, 0); 23 | arrayFree(e); 24 | return list; 25 | } 26 | 27 | char *linkedlistToString(struct ListNode *list) { 28 | int len = linkedlistLength(list); 29 | int *array = malloc(sizeof(int) * len); 30 | 31 | for (int i = 0; i < len; ++i, list = list->next) 32 | array[i] = list->val; 33 | 34 | return arrayToString1D(array, len, ARRAY_INT); 35 | } 36 | 37 | void linkedlistFree(struct ListNode *list) { 38 | struct ListNode *tmp; 39 | while (list) { 40 | tmp = list; 41 | list = list->next; 42 | free(tmp); 43 | } 44 | } 45 | 46 | int linkedlistLength(struct ListNode *list) { 47 | int length = 0; 48 | while (list != NULL) { 49 | list = list->next; 50 | ++length; 51 | } 52 | return length; 53 | } 54 | -------------------------------------------------------------------------------- /c/400-499/415-add-strings.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 思路同 No.43 6 | */ 7 | 8 | #include /* malloc() */ 9 | #include /* strncpy(), strlen(), memset() */ 10 | #include "c/test.h" 11 | 12 | char *addStrings(char *num1, char *num2) { 13 | char *rtn; 14 | int len1 = strlen(num1), len2 = strlen(num2); 15 | if (*num1 == '0') { 16 | return strncpy((rtn = malloc(len2 + 1)), num2, len2 + 1); 17 | } 18 | if (*num2 == '0') { 19 | return strncpy((rtn = malloc(len1 + 1)), num1, len1 + 1); 20 | } 21 | int maxLen = (len1 >= len2 ? len1 : len2) + 1; /* 进位 */ 22 | memset((rtn = malloc(maxLen + 1)), 0, maxLen + 1); 23 | 24 | int v, index1, index2; 25 | for (int i = maxLen - 1; i > 0; --i) { 26 | v = rtn[i]; 27 | if ((index1 = len1 + i - maxLen) >= 0) 28 | v += num1[index1] - '0'; 29 | if ((index2 = len2 + i - maxLen) >= 0) 30 | v += num2[index2] - '0'; 31 | rtn[i] = v % 10; 32 | rtn[i - 1] += v / 10; 33 | } 34 | 35 | int i = 0, flag = rtn[0] == 0 ? 1 : 0; 36 | while (flag < maxLen) 37 | rtn[i++] = rtn[flag++] + '0'; 38 | rtn[i] = '\0'; 39 | return rtn; 40 | } 41 | 42 | void test(const char *expect, char *num1, char *num2) { 43 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, addStrings(num1, num2)); 44 | } 45 | 46 | int main(void) { 47 | test("1", "0", "1"); 48 | test("2", "2", "0"); 49 | test("1008", "999", "9"); 50 | 51 | return testOutput(); 52 | } 53 | -------------------------------------------------------------------------------- /c/400-499/486-predict-the-winner.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * v1: 递归. 很好理解 6 | * v2: 动态规划. 根据递归的结果, 很容易看出数据数据要如何存储 7 | * (感觉动态规划就是将递归的中间变量存储起来) 8 | */ 9 | 10 | #include 11 | #include "c/data-structures/array.h" 12 | #include "c/test.h" 13 | 14 | int max(int a, int b) { return a >= b ? a : b; } 15 | 16 | int pick(int *nums, int beg, int end) { 17 | if (beg == end) return nums[beg]; 18 | return max(nums[beg] - pick(nums, beg+1, end), 19 | nums[end] - pick(nums, beg, end-1)); 20 | } 21 | 22 | bool PredictTheWinner_v1(int *nums, int numsSize) { 23 | return pick(nums, 0, numsSize - 1) >= 0; 24 | } 25 | 26 | bool PredictTheWinner_v2(int *nums, int numsSize) { 27 | int dp[numsSize][numsSize]; 28 | for (int i = 0; i < numsSize; ++i) 29 | dp[i][i] = nums[i]; 30 | 31 | for (int i = 1; i < numsSize; ++i) 32 | for (int j = i-1; j >= 0; --j) 33 | dp[i][j] = max(nums[j] - dp[i][j+1], nums[i] - dp[i-1][j]); 34 | 35 | return dp[numsSize-1][0] >= 0; 36 | } 37 | 38 | void test(bool expect, const char* str) { 39 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 40 | 41 | EXPECT_EQ_INT(expect, PredictTheWinner_v1(arrayValue(e), arraySize(e))); 42 | EXPECT_EQ_INT(expect, PredictTheWinner_v2(arrayValue(e), arraySize(e))); 43 | 44 | arrayFree(e); 45 | } 46 | 47 | int main(void) { 48 | test(false, "[1, 5, 2]"); 49 | test(true, "[1, 5, 233, 7]"); 50 | 51 | return testOutput(); 52 | } 53 | -------------------------------------------------------------------------------- /c/000-099/66-plus-one.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 只需要注意, 所有的数字都是9的情况 6 | */ 7 | 8 | #include 9 | #include /* malloc(), free() */ 10 | #include /* memset() */ 11 | #include "c/data-structures/array.h" 12 | #include "c/test.h" 13 | 14 | int *plusOne(int *digits, int digitsSize, int *returnSize) { 15 | bool allNine = true; 16 | for (int i = 0; i < digitsSize; i++) { 17 | if (digits[i] != 9) { 18 | allNine = false; 19 | break; 20 | } 21 | } 22 | *returnSize = digitsSize + (allNine ? 1 : 0); 23 | int *nums = malloc(sizeof(int) * *returnSize); 24 | 25 | if (allNine) { 26 | memset(nums, 0, sizeof(int) * *returnSize); 27 | nums[0] = 1; 28 | } else { 29 | bool plus = true; 30 | for (int i = digitsSize - 1; i >= 0; i--) { 31 | nums[i] = digits[i] + (plus ? 1 : 0); 32 | plus = nums[i] > 9; 33 | if (plus) nums[i] = 0; 34 | } 35 | } 36 | return nums; 37 | } 38 | 39 | void test(const char *expect, const char *digits) { 40 | arrayEntry *e = arrayParse1D(digits, ARRAY_INT); 41 | 42 | int returnSize = 0; 43 | int *nums = plusOne(arrayValue(e), arraySize(e), &returnSize); 44 | 45 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString1D(nums, returnSize, ARRAY_INT)); 46 | 47 | arrayFree(e); 48 | } 49 | 50 | int main(void) { 51 | test("[1,2,4]", "[1,2,3]"); 52 | test("[4,3,2,2]", "[4,3,2,1]"); 53 | 54 | return testOutput(); 55 | } 56 | -------------------------------------------------------------------------------- /c/data-structures/array.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #ifndef C_DATA_STRUCTURES_ARRAY_H_ 7 | #define C_DATA_STRUCTURES_ARRAY_H_ 8 | 9 | typedef struct arrayEntry arrayEntry; 10 | 11 | typedef enum { 12 | ARRAY_INT, 13 | ARRAY_CHAR, 14 | ARRAY_DOUBLE, 15 | ARRAY_STRING, 16 | } arrayType; 17 | 18 | /* 弃用! 调用方最好直接指定维度 */ 19 | /* arrayEntry *arrayParse(const char *str, arrayType type); */ 20 | arrayEntry *arrayParse1D(const char *str, arrayType type); 21 | arrayEntry *arrayParse2D(const char *str, arrayType type); 22 | 23 | arrayEntry *arrayFrom1D(void *v, int size, arrayType type); 24 | arrayEntry *arrayFrom2D(void *v, int row, int *cols, arrayType type); 25 | arrayEntry *arrayFrom2DSameCol(void *v, int row, int col, arrayType type); 26 | 27 | void arrayFree(arrayEntry *entry); 28 | 29 | char *arrayToString(arrayEntry *entry); 30 | char *arrayToString1D(void *v, int size, arrayType type); 31 | char *arrayToString2D(void *v, int row, int *cols, arrayType type); 32 | char *arrayToString2DSameCol(void *v, int row, int col, arrayType type); 33 | 34 | /* getter, setter */ 35 | void *arrayValue(arrayEntry *entry); 36 | int arraySize(arrayEntry *entry); 37 | void arraySetSize(arrayEntry *entry, int size); 38 | 39 | void arraySetPrecision(arrayEntry *entry, int precision); 40 | 41 | int arrayRow(arrayEntry *entry); 42 | int *arrayCols(arrayEntry *entry); 43 | int arrayCol(arrayEntry *entry); 44 | 45 | #endif /* C_DATA_STRUCTURES_ARRAY_H_ */ 46 | -------------------------------------------------------------------------------- /c/000-099/43-multiply-strings.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 两个大于0的数相乘, 结果的长度一定是两个数的长度和 或 两个数的长度和减1 6 | * 假设, a * b = c, 则 7 | * len(c) == len(a) + len(b) 8 | * OR 9 | * len(c) == len(a) + len(b) - 1 10 | * 然后从低位往高位计算, 最后如果首位为0时, 则字符前移 11 | */ 12 | 13 | #include /* malloc(), memset() */ 14 | #include /* strncpy(), strlen() */ 15 | #include "c/test.h" 16 | 17 | char *multiply(char *num1, char *num2) { 18 | char *rtn; 19 | 20 | if (*num1 == '0' || *num2 == '0') 21 | return strncpy((rtn = malloc(sizeof(char) * 2)), "0", 2); 22 | 23 | int len1 = strlen(num1), len2 = strlen(num2); 24 | memset((rtn = malloc(sizeof(char) * (len1 + len2 + 1))), 0, len1 + len2 + 1); 25 | 26 | for (int i = len1 - 1; i >= 0; --i) { 27 | for (int j = len2 - 1; j >= 0; --j) { 28 | int v = (num1[i] - '0') * (num2[j] - '0') + rtn[i + j + 1]; 29 | rtn[i + j + 1] = v % 10; 30 | rtn[i + j] += v / 10; 31 | } 32 | } 33 | 34 | int i = 0, flag = rtn[0] == 0 ? 1 : 0; 35 | while (flag < len1 + len2) 36 | rtn[i++] = rtn[flag++] + '0'; 37 | rtn[i] = '\0'; 38 | return rtn; 39 | } 40 | 41 | void test(const char *expect, char *num1, char *num2) { 42 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, multiply(num1, num2)); 43 | } 44 | 45 | int main(void) { 46 | test("0", "0", "0"); 47 | test("1", "1", "1"); 48 | test("98901", "99", "999"); 49 | test("1000", "10", "100"); 50 | 51 | return testOutput(); 52 | } 53 | -------------------------------------------------------------------------------- /c/200-299/287-find-the-duplicate-number.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * https://leetcode.com/problems/find-the-duplicate-number/ 6 | * Q: 在一个长度为n+1的数组中, 里面是元素是 [1, n], 只有一个数字是重复的, 找到它 7 | * (不允许修改数字的元素; 使用常量空间; 1 <= n <= 100000) 8 | * 9 | * 第一次读题, 以为是一个数字出现2次, 其他数字都出现了1次, 这不用数学运算就能计算出来么, 然后就被 [2,2,2,2,2] 的测试用例教育了. 10 | * 不允许修改数字元素+使用常量空间, 就排除了排序法、利用数组空间标记法、位存储法... 11 | * 12 | * 看了解题思路, 只有这个解符合规定: https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare 13 | */ 14 | 15 | #include "c/data-structures/array.h" 16 | #include "c/test.h" 17 | 18 | int findDuplicate(int *nums, int numsSize) { 19 | // 乌龟走一步, 兔子走两步, 直到相遇 20 | int tortoise = nums[0], hare = nums[0]; 21 | do { 22 | tortoise = nums[tortoise]; 23 | hare = nums[nums[hare]]; 24 | } while (tortoise != hare); 25 | 26 | // 相遇后, 乌龟去起点, 双方每次走一步, 相遇的地方就是环状起点 27 | tortoise = nums[0]; 28 | 29 | while (tortoise != hare) { 30 | tortoise = nums[tortoise]; 31 | hare = nums[hare]; 32 | } 33 | 34 | return hare; 35 | } 36 | 37 | void test(int expect, const char *nums) { 38 | arrayEntry *e = arrayParse1D(nums, ARRAY_INT); 39 | 40 | EXPECT_EQ_INT(expect, findDuplicate(arrayValue(e), arraySize(e))); 41 | 42 | arrayFree(e); 43 | } 44 | 45 | int main(void) { 46 | test(2, "[1,3,4,2,2]"); 47 | test(3, "[3,1,3,4,2]"); 48 | 49 | // 以下是提交错误时的测试用例 50 | test(2, "[2,2,2,2,2]"); 51 | test(9, "[2,5,9,6,9,3,8,9,7,1]"); 52 | 53 | return testOutput(); 54 | } 55 | -------------------------------------------------------------------------------- /c/400-499/496-next-greater-element-i.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include /* malloc() */ 7 | #include "c/data-structures/array.h" 8 | #include "c/test.h" 9 | 10 | /** 11 | * Return an array of size *returnSize. 12 | * Note: The returned array must be malloced, assume caller calls free(). 13 | */ 14 | int *nextGreaterElement(int *findNums, int findNumsSize, int *nums, int numsSize, int *returnSize) { 15 | int* rtn = malloc(sizeof(int) * findNumsSize); 16 | for (int i = 0; i < findNumsSize; ++i) { 17 | int j = 0; 18 | while (nums[j] != findNums[i]) j++; 19 | 20 | for (; j < numsSize; ++j) { 21 | if (nums[j] > findNums[i]) { 22 | rtn[i] = nums[j]; 23 | break; 24 | } 25 | } 26 | if (j == numsSize) rtn[i] = -1; 27 | } 28 | *returnSize = findNumsSize; 29 | return rtn; 30 | } 31 | 32 | void test(const char* expect, const char* str1, const char* str2) { 33 | arrayEntry *e1 = arrayParse1D(str1, ARRAY_INT); 34 | arrayEntry *e2 = arrayParse1D(str2, ARRAY_INT); 35 | int returnSize; 36 | int *a = nextGreaterElement(arrayValue(e1), arraySize(e1), arrayValue(e2), arraySize(e2), &returnSize); 37 | 38 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString1D(a, returnSize, ARRAY_INT)); 39 | 40 | arrayFree(e1); 41 | arrayFree(e2); 42 | } 43 | 44 | int main(void) { 45 | test("[-1,3,-1]", "[4,1,2]", "[1,3,4,2]"); 46 | test("[3,-1]", "[2,4]", "[1,2,3,4]"); 47 | 48 | return testOutput(); 49 | } 50 | -------------------------------------------------------------------------------- /c/900-999/990-satisfiability-of-equality-equations.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 先计算所有的‘==’, 分好组 6 | * 再计算所有的‘!=’, 如有同组的, 则 false 7 | * 8 | * 分组: 因为只要26个字母, 所以最多26个组, 然后对于每个等式, 把他们以递归的方式找到根部, 然后串起来 9 | */ 10 | 11 | #include 12 | #include 13 | #include "c/data-structures/array.h" 14 | #include "c/test.h" 15 | 16 | int find(int8_t data[], int x) { 17 | if (data[x] == x) return x; 18 | return find(data, data[x]); 19 | } 20 | 21 | bool equationsPossible(char **equations, int equationsSize) { 22 | int8_t data[26]; 23 | for (int i = 0; i < 26; i++) data[i] = i; 24 | 25 | for (int i = 0; i < equationsSize; i++) { 26 | if (equations[i][1] == '=') { 27 | data[find(data, equations[i][0] - 'a')] = find(data, equations[i][3] - 'a'); 28 | } 29 | } 30 | 31 | for (int i = 0; i < equationsSize; i++) { 32 | if (equations[i][1] != '=') { 33 | if (find(data, data[equations[i][0] - 'a']) == find(data, data[equations[i][3] - 'a'])) { 34 | return false; 35 | } 36 | } 37 | } 38 | 39 | return true; 40 | } 41 | 42 | void test(bool expect, const char *equations) { 43 | arrayEntry *e = arrayParse1D(equations, ARRAY_STRING); 44 | EXPECT_EQ_INT(expect, equationsPossible(arrayValue(e), arraySize(e))); 45 | arrayFree(e); 46 | } 47 | 48 | int main(void) { 49 | test(false, "[a==b,b!=a]"); 50 | test(true, "[a==b,b==a]"); 51 | 52 | test(false, "[f==a,a==b,f!=e,a==c,b==e,c==f]"); 53 | 54 | return testOutput(); 55 | } 56 | -------------------------------------------------------------------------------- /c/000-099/05-longest-palindromic-substring.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * https://leetcode.com/articles/longest-palindromic-substring/#approach-4-expand-around-center-accepted 6 | */ 7 | 8 | #include /* malloc() */ 9 | #include /* strlen(), strncpy() */ 10 | #include "c/test.h" 11 | 12 | int expandAroundCenter(char *s, int l, size_t r) { 13 | while (l >=0 && r < strlen(s) && s[l] == s[r]) { 14 | l--; 15 | r++; 16 | } 17 | return r - l - 1; /* r - l + 1 - 2 */ 18 | } 19 | 20 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 21 | char *longestPalindrome(char *s) { 22 | int begin = 0, end = 0; 23 | size_t i; 24 | 25 | for (i = 0; i != strlen(s); ++i) { 26 | int len1 = expandAroundCenter(s, i, i); 27 | int len2 = expandAroundCenter(s, i, i + 1); 28 | int len = MAX(len1, len2); 29 | if (len > end - begin) { 30 | begin = i - (len - 1) / 2; 31 | end = i + len / 2; 32 | } 33 | } 34 | int size = end - begin + 1; 35 | char *rt = malloc(sizeof(char) * (size + 1)); 36 | rt[size] = '\0'; 37 | return strncpy(rt, &s[begin], size); 38 | } 39 | 40 | void test(const char *expect, char *s) { 41 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, longestPalindrome(s)); 42 | } 43 | 44 | /* 45 | Input: "babad" 46 | Output: "bab" 47 | Note: "aba" is also a valid answer. 48 | 49 | Input: "cbbd" 50 | Output: "bb" 51 | */ 52 | int main() { 53 | test("aba", "babad"); 54 | test("bb", "cbbd"); 55 | 56 | return testOutput(); 57 | } 58 | -------------------------------------------------------------------------------- /c/400-499/448-find-all-numbers-disappeared-in-an-array.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 题目要求不使用额外的空间, 那么一定是利用原空间移动数字 6 | * 提交后, 排名很中庸 7 | * 查看了一下其他人的答案 8 | * 速度最快: 分配新的数组, 然后用旧的数据填空, 最后移动想到的内容到数组的前面 9 | * 内存最少: 返回的数组使用输入的数组(但应该是不符合规定吧?) 10 | */ 11 | 12 | #include "c/data-structures/array.h" 13 | #include "c/test.h" 14 | 15 | /** 16 | * Note: The returned array must be malloced, assume caller calls free(). 17 | */ 18 | int *findDisappearedNumbers(int *nums, int numsSize, int *returnSize) { 19 | int c = 0; 20 | for (int i = 0; i < numsSize; ++i) { 21 | while (nums[i] != 0 && nums[i] != i + 1) { 22 | if (nums[i] == nums[nums[i] - 1]) { 23 | nums[i] = 0; 24 | ++c; 25 | } else { 26 | int tmp = nums[nums[i] - 1]; 27 | nums[nums[i] - 1] = nums[i]; 28 | nums[i] = tmp; 29 | } 30 | } 31 | } 32 | *returnSize = 0; 33 | int *rtn = malloc(sizeof(int) * c); 34 | for (int i = 0; i < numsSize; ++i) { 35 | if (nums[i] == 0) { 36 | rtn[(*returnSize)++] = i + 1; 37 | } 38 | } 39 | return rtn; 40 | } 41 | 42 | void test(const char *expect, const char *str) { 43 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 44 | int returnSize; 45 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString1D(findDisappearedNumbers(arrayValue(e), arraySize(e), &returnSize), returnSize, ARRAY_INT)); 46 | arrayFree(e); 47 | } 48 | 49 | int main(void) { 50 | test("[5,6]", "[4,3,2,7,8,2,3,1]"); 51 | test("[2]", "[1,1]"); 52 | 53 | return testOutput(); 54 | } 55 | -------------------------------------------------------------------------------- /Shell.sh: -------------------------------------------------------------------------------- 1 | # https://leetcode.com/problemset/shell/ 2 | :< 3 | * All rights reserved. 4 | * 5 | * 朴素方法, 模拟自然书写(速度比较慢) 6 | * 7 | * ps. 更简单的方法是定义几个常量 -> 个位0-9, 十位0-9, 百位0-9, 千位0-3 8 | * 然后根据给定的数字从高位到低位依次转换并拼接起来 9 | */ 10 | 11 | #include /* pow() */ 12 | #include /* malloc() */ 13 | #include "c/test.h" 14 | 15 | const char T[4][3] = { 16 | /*1 5 10 */ 17 | {'M', ' ', ' '}, /* thousand */ 18 | {'C', 'D', 'M'}, /* hundred */ 19 | {'X', 'L', 'C'}, /* ten */ 20 | {'I', 'V', 'X'} /* one */ 21 | }; 22 | 23 | char *intToRoman(int num) { 24 | /* 在3999内, 最长的结果是 3888(MMMDCCCLXXXVIII) */ 25 | char *rt = malloc(sizeof(char) * 16); /* 15 + 1 */ 26 | char *p = rt; 27 | 28 | int i, v, bit; 29 | for (i = 0; i < 4; i++) { 30 | bit = pow(10, 3 - i); /* 0 -> 1000, 1 -> 100, 2 -> 10, 3 -> 1 */ 31 | v = num / bit; 32 | if (v != 0) { 33 | if (bit != 1) num %= bit; 34 | if (v == 9) { 35 | *p++ = T[i][0]; 36 | *p++ = T[i][2]; 37 | } else if (v == 4) { 38 | *p++ = T[i][0]; 39 | *p++ = T[i][1]; 40 | } else { 41 | if (v >= 5) { 42 | v -= 5; 43 | *p++ = T[i][1]; 44 | } 45 | while (v--) *p++ = T[i][0]; 46 | } 47 | } 48 | } 49 | *p = '\0'; 50 | return rt; 51 | } 52 | 53 | void test(const char *expect, int num) { 54 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, intToRoman(num)); 55 | } 56 | 57 | int main(void) { 58 | test("I", 1); 59 | test("IV", 4); 60 | test("MMMDCCCLXXXVIII", 3888); 61 | 62 | return testOutput(); 63 | } 64 | -------------------------------------------------------------------------------- /c/000-099/22-generate-parentheses.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 递归解法, 参考了 OJ 上更优雅的写法 6 | */ 7 | 8 | #include /* malloc(), free() */ 9 | #include /* strncpy() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | void generate(char **rt, int *returnSize, int l, int r, char *tmp, int index) { 14 | if (l == 0 && r == 0) { 15 | tmp[index] = '\0'; 16 | strncpy(rt[(*returnSize)++] = malloc(index + 1), tmp, index + 1); 17 | return; 18 | } 19 | 20 | if (l > 0) { 21 | tmp[index] = '('; 22 | generate(rt, returnSize, l-1, r, tmp, index+1); 23 | } 24 | 25 | if (r > 0 && r > l) { 26 | tmp[index] = ')'; 27 | generate(rt, returnSize, l, r-1, tmp, index+1); 28 | } 29 | } 30 | 31 | /** 32 | * Return an array of size *returnSize. 33 | * Note: The returned array must be malloced, assume caller calls free(). 34 | */ 35 | char **generateParenthesis(int n, int *returnSize) { 36 | char **rt = malloc(sizeof(char*) * 5000); /* TODO: 如何根据N计算出最大容量 */ 37 | char *tmp = malloc(sizeof(char) * (2*n+1)); 38 | *returnSize = 0; 39 | generate(rt, returnSize, n, n, tmp, 0); 40 | free(tmp); 41 | return rt; 42 | } 43 | 44 | void test(const char* expect, int n) { 45 | int returnSize; 46 | char** actual = generateParenthesis(n, &returnSize); 47 | 48 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString1D(actual, returnSize, ARRAY_STRING)); 49 | } 50 | 51 | int main(void) { 52 | test("[((())),(()()),(())(),()(()),()()()]", 3); 53 | 54 | return testOutput(); 55 | } 56 | -------------------------------------------------------------------------------- /c/1200-1299/1220-count-vowels-permutation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 明显动态规划, 按照判断元音字母的下一个是什么的思路找下去, 没有结果 6 | * 于是反过来在思考一番, 则有有规律可寻, 具体见下方注释 7 | * 8 | * 第一次提交时int越界, 在网站自定义了几个值对比, 发现我的答案明显大于标准答案很多. 9 | * 仔细身体才发现 "10^9 + 7" 10 | * 审题不仔细... 11 | * 12 | * AC 后发现耗时 12ms, 看到最佳是 4ms, 于是想着优化了一番 13 | * 1. 从 2层循环 换成 1层循环, => 8ms 14 | * 2. 实在想不出结果, 看了4ms的答案, 把数据类型从 long 换成 unsigned int => 4ms 15 | */ 16 | 17 | #include "c/test.h" 18 | 19 | int MOD = 1e9 + 7; /* Since the answer may be too large, return it modulo 10^9 + 7. */ 20 | int countVowelPermutation(int n) { 21 | if (n <= 0) return 0; 22 | if (n == 1) return 5; 23 | 24 | unsigned int dp[2][5] = {{1, 1, 1, 1, 1}}; 25 | unsigned int *p, *p1 = dp[0], *p2 = dp[1]; 26 | 27 | for (int i = 1; i < n; i++) { 28 | /* 0, 1, 2, 3, 4 */ 29 | /* a, e, i, o, u */ 30 | 31 | /* a = e + i + u */ 32 | p2[0] = (p1[1] + p1[2] + p1[4]) % MOD; 33 | /* e = a + i */ 34 | p2[1] = (p1[0] + p1[2]) % MOD; 35 | /* i = e + o */ 36 | p2[2] = (p1[1] + p1[3]) % MOD; 37 | /* o = i */ 38 | p2[3] = p1[2]; 39 | /* u = i + o */ 40 | p2[4] = (p1[2] + p1[3]) % MOD; 41 | 42 | /* 交换 p1, p2 */ 43 | p = p1; p1 = p2; p2 = p; 44 | } 45 | 46 | return (p1[0] + p1[1] + p1[2] + p1[3] + p1[4]) % MOD; 47 | } 48 | 49 | void test(int expect, int n) { 50 | EXPECT_EQ_INT(expect, countVowelPermutation(n)); 51 | } 52 | 53 | int main(void) { 54 | test(5, 1); 55 | test(10, 2); 56 | test(68, 5); 57 | 58 | test(18208803, 144); 59 | 60 | return testOutput(); 61 | } 62 | -------------------------------------------------------------------------------- /c/800-899/844-backspace-string-compare.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 刚读题目的时候, 很容易就会想到, 此类问题用栈来解很容易. 6 | * 但题目的最后规定是 时间: O(N), 空间: O(1). 7 | * 所以就不能使用栈, 因为栈的空间是O(N). 8 | * 9 | * 那么大概率就是用两个指针来解题. 10 | * 从前向后找时, 会发现需要依赖后面的'#', 但无法得知后面的'#'有几个. 11 | * 因此, 两个指针应该是从后向前移动. 12 | * 13 | * 时间: O(len(S) + len(T) + while(len(S)) + while(len(T))) 14 | * => O(2 * (len(S) + len(T))) 15 | * => O(4N) 16 | * => O(N) 17 | */ 18 | 19 | #include 20 | #include 21 | #include "c/test.h" 22 | 23 | bool backspaceCompare(char *S, char *T) { 24 | int i1 = strlen(S) - 1, i2 = strlen(T) - 1; 25 | int c1 = 0, c2 = 0; 26 | while (i1 >= 0 || i2 >= 0) { 27 | while (i1 >= 0) { 28 | if (S[i1] == '#') 29 | ++c1, --i1; 30 | else if (c1 > 0) 31 | --c1, --i1; 32 | else 33 | break; 34 | } 35 | 36 | while (i2 >= 0) { 37 | if (T[i2] == '#') 38 | ++c2, --i2; 39 | else if (c2 > 0) 40 | --c2, --i2; 41 | else 42 | break; 43 | } 44 | 45 | if (i1 >= 0 && i2 >= 0 && S[i1] != T[i2]) { 46 | return false; 47 | } 48 | --i1, --i2; 49 | } 50 | return i1 == i2; 51 | } 52 | 53 | void test(bool expect, char *S, char *T) { 54 | EXPECT_EQ_INT(expect, backspaceCompare(S, T)); 55 | } 56 | 57 | int main(void) { 58 | test(true, "ab#c", "ad#c"); 59 | test(true, "ab##", "c#c#"); 60 | test(true, "a##c", "#a#c"); 61 | test(false, "a#c", "b"); 62 | 63 | test(false, "bxj##tw", "bxj###tw"); 64 | 65 | return testOutput(); 66 | } 67 | -------------------------------------------------------------------------------- /c/700-799/741-network-delay-time.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 用二维数组标记图的联通关系, dfs 更新每个点的数值, 最后统计最大值. 6 | */ 7 | 8 | #include 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | void dfs(int *nodes, int *data, int N, int k) { 13 | for (int i = 0; i < N; i++) { 14 | int time = nodes[k * N + i]; 15 | if (time >= 0) { 16 | time += data[k]; 17 | if (data[i] == -1 || data[i] > time) { 18 | data[i] = time; 19 | dfs(nodes, data, N, i); 20 | } 21 | } 22 | } 23 | } 24 | 25 | int networkDelayTime(int **times, int timesSize, int *timesColSize, int N, int K) { 26 | int nodes[N][N]; 27 | int data[N]; 28 | for (int i = 0; i < N; i++) { 29 | data[i] = -1; 30 | for (int j = 0; j < N; j++) 31 | nodes[i][j] = -1; 32 | } 33 | 34 | for (int i = 0; i < timesSize; i++) { 35 | nodes[times[i][0] - 1][times[i][1] - 1] = times[i][2]; 36 | } 37 | 38 | data[K - 1] = 0; 39 | dfs(*nodes, data, N, K - 1); 40 | 41 | int time = 0; 42 | for (int i = 0; i < N; i++) { 43 | if (data[i] < 0) return -1; 44 | if (data[i] > time) time = data[i]; 45 | } 46 | return time; 47 | } 48 | 49 | void test(int expect, char *s, int N, int K) { 50 | arrayEntry *e = arrayParse2D(s, ARRAY_INT); 51 | 52 | EXPECT_EQ_INT(expect, networkDelayTime(arrayValue(e), arrayRow(e), arrayCols(e), N, K)); 53 | 54 | arrayFree(e); 55 | } 56 | 57 | int main(void) { 58 | test(2, "[[2,1,1],[2,3,1],[3,4,1]]", 4, 2); 59 | 60 | test(3, "[[1,2,1],[2,1,3]]", 2, 2); 61 | 62 | return testOutput(); 63 | } 64 | -------------------------------------------------------------------------------- /c/500-599/539-minimum-time-difference.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 因为时间的种类在1440, 而题目的数量最大是20000, 所以维护一个bool数组, 最后计算一个最小距离 6 | */ 7 | 8 | #include 9 | #include /* memset() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | #define SIZE 24*60 14 | 15 | int findMinDifference(char **timePoints, int timePointsSize) { 16 | bool flag[SIZE]; 17 | memset(flag, 0, sizeof(bool) * SIZE); 18 | 19 | for (int i = 0; i < timePointsSize; i++) { 20 | int index = 21 | (timePoints[i][0] - '0') * 600 + 22 | (timePoints[i][1] - '0') * 60 + 23 | (timePoints[i][3] - '0') * 10 + 24 | (timePoints[i][4] - '0'); 25 | if (flag[index]) return 0; 26 | flag[index] = true; 27 | } 28 | 29 | int rtn = SIZE; 30 | int first_index = -1; 31 | int last_index; 32 | for (int i = 0; i < SIZE; i++) { 33 | if (flag[i]) { 34 | if (first_index < 0) { 35 | first_index = i; 36 | last_index = i; 37 | } else { 38 | int v = i - last_index; 39 | if (v < rtn) rtn = v; 40 | } 41 | last_index = i; 42 | } 43 | } 44 | int v = first_index - last_index + SIZE; 45 | if (v < rtn) rtn = v; 46 | return rtn; 47 | } 48 | 49 | void test(int expect, const char *str) { 50 | arrayEntry *e = arrayParse1D(str, ARRAY_STRING); 51 | 52 | EXPECT_EQ_INT(expect, findMinDifference(arrayValue(e), arraySize(e))); 53 | 54 | arrayFree(e); 55 | } 56 | 57 | int main(void) { 58 | test(1, "[23:59, 00:00]"); 59 | test(0, "[00:00, 23:59, 00:00]"); 60 | 61 | return testOutput(); 62 | } 63 | -------------------------------------------------------------------------------- /c/000-099/34-search-for-a-range.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 题目要求时间复杂度是 O(log n), 所以二分查找 6 | */ 7 | 8 | #include 9 | #include /* malloc() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | /** 14 | * Return an array of size *returnSize. 15 | * Note: The returned array must be malloced, assume caller calls free(). 16 | */ 17 | int* searchRange(int *nums, int numsSize, int target, int *returnSize) { 18 | *returnSize = 2; 19 | int x = -1, y = -1; 20 | int a = 0, b = numsSize - 1, i; 21 | while (a <= b) { 22 | i = (a + b) / 2; 23 | if (nums[i] < target) { 24 | a = i + 1; 25 | } else if (nums[i] > target) { 26 | b = i - 1; 27 | } else { 28 | x = y = i; 29 | while (x > 0 && nums[x-1] == target) x--; 30 | while (y < numsSize - 1 && nums[y+1] == target) y++; 31 | break; 32 | } 33 | } 34 | int *rtn = malloc(sizeof(int) * *returnSize); 35 | rtn[0] = x; 36 | rtn[1] = y; 37 | return rtn; 38 | } 39 | 40 | void test(const char *expect, const char *str, int target) { 41 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 42 | int returnSize; 43 | int* a = searchRange(arrayValue(e), arraySize(e), target, &returnSize); 44 | 45 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString1D(a, returnSize, ARRAY_INT)); 46 | 47 | arrayFree(e); 48 | } 49 | 50 | /* 51 | Given [5, 7, 7, 8, 8, 10] and target value 8, 52 | return [3, 4]. 53 | */ 54 | int main(void) { 55 | test("[3,4]", "[5,7,7,8,8,10]", 8); 56 | test("[-1,-1]", "[]", 0); 57 | 58 | return testOutput(); 59 | } 60 | -------------------------------------------------------------------------------- /c/600-699/678-valid-parenthesis-string.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 看到括号匹配, 很容易想到用栈来解决 6 | * 由于'*'可以匹配任何字符串, 所以弹出的时候优先弹出'(' 7 | * 最后尝试将剩余的'(', 用'*'来匹配 8 | */ 9 | 10 | #include 11 | #include "c/test.h" 12 | 13 | struct stack { 14 | int size; 15 | char data[100]; /* The string size will be in the range [1, 100] */ 16 | }; 17 | 18 | bool pop(struct stack *s) { 19 | if (s->size == 0) return false; 20 | /* 如果不为空, 一定能匹配到 */ 21 | int i = s->size-- - 1; 22 | while (i != 0) { 23 | if (s->data[i] == '(') break; /* 优先匹配'(', 其次匹配'*' */ 24 | i--; 25 | } 26 | s->data[i] = '*'; 27 | return true; 28 | } 29 | 30 | void push(struct stack *s, int v) { 31 | s->data[s->size++] = v; 32 | } 33 | 34 | bool isValid(struct stack *s) { 35 | if (s->size > 0) { 36 | int n = 0; 37 | for (int i = s->size - 1; i >= 0; i--) { 38 | s->data[i] == '*' ? n++ : n--; 39 | if (n < 0) return false; 40 | } 41 | } 42 | 43 | return true; 44 | } 45 | 46 | bool checkValidString(char *s) { 47 | struct stack stack = {}; 48 | while (*s != '\0') { 49 | if (*s != ')') 50 | push(&stack, *s); 51 | else if (!pop(&stack)) 52 | return false; 53 | s++; 54 | } 55 | 56 | return isValid(&stack); 57 | } 58 | 59 | void test(bool expect, char *s) { 60 | EXPECT_EQ_INT(expect, checkValidString(s)); 61 | } 62 | 63 | int main(void) { 64 | test(true, "()"); 65 | test(true, "(*)"); 66 | test(true, "(*))"); 67 | 68 | test(true, "(*()"); 69 | test(false, "(())((())()()(*)(*()(())())())()()((()())((()))(*"); 70 | 71 | return testOutput(); 72 | } 73 | -------------------------------------------------------------------------------- /c/200-299/200-number-of-islands.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 找到一个为 '1' 的位置,然后按4个方向开始感染 6 | */ 7 | 8 | #include "c/data-structures/array.h" 9 | #include "c/test.h" 10 | 11 | void infect(char **grid, int gridRowSize, int gridColSize, int x, int y) { 12 | if (grid[x][y] == '1') { 13 | grid[x][y] = '0'; 14 | if (x > 0) 15 | infect(grid, gridRowSize, gridColSize, x - 1, y); 16 | if (x < gridRowSize - 1) 17 | infect(grid, gridRowSize, gridColSize, x + 1, y); 18 | if (y > 0) 19 | infect(grid, gridRowSize, gridColSize, x, y - 1); 20 | if (y < gridColSize - 1) 21 | infect(grid, gridRowSize, gridColSize, x, y + 1); 22 | } 23 | } 24 | 25 | int numIslands(char **grid, int gridSize, int *gridColSize) { 26 | int rtn = 0; 27 | for (int i = 0; i < gridSize; ++i) { 28 | for (int j = 0; j < gridColSize[i]; ++j) { 29 | if (grid[i][j] == '1') { 30 | ++rtn; 31 | infect(grid, gridSize, gridColSize[i], i, j); 32 | } 33 | } 34 | } 35 | return rtn; 36 | } 37 | 38 | void test(int expect, const char *str) { 39 | arrayEntry *e = arrayParse2D(str, ARRAY_CHAR); 40 | 41 | EXPECT_EQ_INT(expect, numIslands(arrayValue(e), arrayRow(e), arrayCols(e))); 42 | 43 | arrayFree(e); 44 | } 45 | 46 | int main(void) { 47 | test(1, 48 | "[" 49 | "[1,1,1,1,0]," 50 | "[1,1,0,1,0]," 51 | "[1,1,0,0,0]," 52 | "[0,0,0,0,0]" 53 | "]"); 54 | 55 | test(3, 56 | "[" 57 | "[1,1,0,0,0]," 58 | "[1,1,0,0,0]," 59 | "[0,0,1,0,0]," 60 | "[0,0,0,1,1]" 61 | "]"); 62 | 63 | return testOutput(); 64 | } 65 | -------------------------------------------------------------------------------- /c/000-099/93-restore-ip-addresses.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) 2017, Saul Lawliet 4 | * All rights reserved. 5 | * 6 | * 递归解就可以了 7 | */ 8 | 9 | #include /* snprintf */ 10 | #include /* malloc(), free() */ 11 | #include "c/data-structures/array.h" 12 | #include "c/test.h" 13 | 14 | #define MAX_SIZE 20 15 | 16 | void loop(char **rtn, int *returnSize, char *s, int *a, int i) { 17 | if (i > 3) { 18 | if (*s == '\0') { 19 | int sz = snprintf(NULL, 0, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); 20 | snprintf(rtn[(*returnSize)++] = malloc(sz + 1), sz + 1, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); 21 | } 22 | return; 23 | } 24 | int x = 0; 25 | char *p = s; 26 | while (*p) { 27 | x = x * 10 + (*p++ - '0'); 28 | if (x <= 255) { 29 | a[i] = x; 30 | loop(rtn, returnSize, p, a, i+1); 31 | } 32 | if (x == 0 || x > 255) break; 33 | } 34 | } 35 | 36 | /** 37 | * Return an array of size *returnSize. 38 | * Note: The returned array must be malloced, assume caller calls free(). 39 | */ 40 | char **restoreIpAddresses(char *s, int *returnSize) { 41 | int *a = malloc(sizeof(int) * 4); 42 | char **rtn = malloc(sizeof(char*) * MAX_SIZE); 43 | *returnSize = 0; 44 | loop(rtn, returnSize, s, a, 0); 45 | free(a); 46 | return rtn; 47 | } 48 | 49 | void test(const char *expect, char *s) { 50 | int returnSize; 51 | char **a = restoreIpAddresses(s, &returnSize); 52 | 53 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString1D(a, returnSize, ARRAY_STRING)); 54 | } 55 | 56 | int main(void) { 57 | test("[255.255.11.135,255.255.111.35]", "25525511135"); 58 | test("[]", "00003"); 59 | 60 | return testOutput(); 61 | } 62 | -------------------------------------------------------------------------------- /c/tools/queue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/tools/queue.h" 7 | #include /* assert() */ 8 | #include /* malloc(), free(), realloc() */ 9 | 10 | struct Queue *queueMake() { 11 | struct Queue *q = malloc(sizeof(struct Queue)); 12 | q->front = q->rear = 0; 13 | q->size = QUEUE_INIT_SIZE; 14 | q->array = malloc(sizeof(void *) * q->size); 15 | return q; 16 | } 17 | 18 | void queueFree(struct Queue *q) { 19 | free(q->array); 20 | free(q); 21 | } 22 | 23 | bool queueIsEmpty(struct Queue *q) { 24 | return q->rear == q->front; 25 | } 26 | 27 | static void reverse(void *R[], int from, int to) { 28 | void *temp; 29 | for (int i = 0; i < (to - from + 1) / 2; ++i) { 30 | temp = R[from + i]; 31 | R[from + i] = R[to - i]; 32 | R[to - i] = temp; 33 | } 34 | } 35 | 36 | static void repair(struct Queue *q) { 37 | if (q->front == 0) return; 38 | reverse(q->array, 0, q->front-1); 39 | reverse(q->array, q->front, q->size-1); 40 | reverse(q->array, 0, q->size-1); 41 | q->front = 0; 42 | q->rear = q->size - 1; 43 | } 44 | 45 | static bool isFull(struct Queue *q) { 46 | return (q->rear + 1) % q->size == q->front; 47 | } 48 | 49 | void queueOffer(struct Queue *q, void *e) { 50 | if (isFull(q)) { 51 | repair(q); 52 | q->size += q->size >> 1; /* q->size * 1.5 */ 53 | q->array = realloc(q->array, sizeof(void *) * q->size); 54 | } 55 | q->array[q->rear++] = e; 56 | if (q->rear == q->size) q->rear = 0; 57 | } 58 | 59 | void *queuePoll(struct Queue *q) { 60 | assert(!queueIsEmpty(q)); 61 | void *e = q->array[q->front++]; 62 | if (q->front == q->size) q->front = 0; 63 | return e; 64 | } 65 | -------------------------------------------------------------------------------- /c/000-099/59-spiral-matrix-ii.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 区别于 54-spiral-matrix 是画4条边, 这个是画圈. 6 | */ 7 | 8 | #include /* malloc() */ 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | int **generateMatrix(int n, int *returnSize, int **returnColumnSizes) { 13 | *returnSize = n; 14 | if (n == 0) { 15 | *returnColumnSizes = NULL; 16 | return NULL; 17 | } 18 | 19 | *returnColumnSizes = malloc(sizeof(int) * n); 20 | int **matrix = malloc(sizeof(int *) * n); 21 | for (int i = 0; i < n; ++i) { 22 | (*returnColumnSizes)[i] = n; 23 | matrix[i] = malloc(sizeof(int) * n); 24 | } 25 | 26 | for (int loop = 0, cur = 0; loop < (n + 1) / 2; ++loop) { 27 | int ceil = n - loop - 1; 28 | if (ceil == loop) { 29 | matrix[loop][loop] = ++cur; 30 | break; 31 | } 32 | for (int i = loop; i < ceil; ++i) matrix[loop][i] = ++cur; 33 | for (int i = loop; i < ceil; ++i) matrix[i][ceil] = ++cur; 34 | for (int i = ceil; i > loop; --i) matrix[ceil][i] = ++cur; 35 | for (int i = ceil; i > loop; --i) matrix[i][loop] = ++cur; 36 | } 37 | 38 | return matrix; 39 | } 40 | 41 | void test(const char *expect, int n) { 42 | int returnSize; 43 | int *returnColumnSizes; 44 | int **matrix = generateMatrix(n, &returnSize, &returnColumnSizes); 45 | 46 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString2D(matrix, returnSize, returnColumnSizes, ARRAY_INT)); 47 | } 48 | 49 | int main(void) { 50 | test("[[1,2,3],[8,9,4],[7,6,5]]", 3); 51 | 52 | test("[]", 0); 53 | test("[[1]]", 1); 54 | test("[[1,2,3,4],[12,13,14,5],[11,16,15,6],[10,9,8,7]]", 4); 55 | 56 | return testOutput(); 57 | } 58 | -------------------------------------------------------------------------------- /c/2300-2399/2352-equal-row-and-column-pairs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2023, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 直观感觉这道题不应该算中等难度, 解题的过程中有两个问题 6 | * 1. hash越界 7 | * 解决方法: 对10000007取模 8 | * 2. hash一致但数组不相等 9 | * 解决方法: hash一致的情况也继续对比数组是否相等 10 | */ 11 | 12 | #include "c/data-structures/array.h" 13 | #include "c/test.h" 14 | 15 | int equalPairs(int **grid, int gridSize, int *gridColSize) { 16 | int *rowHash = malloc(sizeof(int) * gridSize); 17 | int *colHash = malloc(sizeof(int) * gridSize); 18 | 19 | for (int i = 0; i < gridSize; i++) { 20 | rowHash[i] = 1; 21 | colHash[i] = 1; 22 | } 23 | 24 | for (int i = 0; i < gridSize; i++) { 25 | for (int j = 0; j < gridSize; j++) { 26 | rowHash[i] = (rowHash[i] * 31 + grid[i][j]) % 10000007; 27 | colHash[i] = (colHash[i] * 31 + grid[j][i]) % 10000007; 28 | } 29 | } 30 | 31 | int rt = 0; 32 | for (int i = 0; i < gridSize; i++) { 33 | for (int j = 0; j < gridSize; j++) { 34 | if (rowHash[i] == colHash[j]) { 35 | // hash 一致, 也要对比每一项 36 | for (int k = 0; k < gridSize; k++) { 37 | if (grid[i][k] != grid[k][j]) break; 38 | if (k == gridSize - 1) rt++; 39 | } 40 | } 41 | } 42 | } 43 | 44 | free(colHash); 45 | free(rowHash); 46 | 47 | return rt; 48 | } 49 | 50 | void test(int except, char *grid) { 51 | arrayEntry *e = arrayParse2D(grid, ARRAY_INT); 52 | EXPECT_EQ_INT(except, equalPairs(arrayValue(e), arrayRow(e), arrayCols(e))); 53 | arrayFree(e); 54 | } 55 | 56 | int main(void) { 57 | test(1, "[[3,2,1],[1,7,6],[2,7,7]]"); 58 | test(3, "[[3,1,2,2],[1,4,4,5],[2,4,2,2],[2,4,2,2]]"); 59 | test(0, "[[2,1],[3,32]]"); 60 | 61 | return testOutput(); 62 | } 63 | -------------------------------------------------------------------------------- /c/000-099/20-valid-parentheses.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 使用 stack, 即可轻松解决 6 | */ 7 | 8 | #include /* assert() */ 9 | #include 10 | #include /* malloc(), free() */ 11 | #include /* strlen() */ 12 | #include "c/test.h" 13 | 14 | struct StackRecord{ 15 | int top; 16 | char *array; 17 | }; 18 | typedef struct StackRecord * stack; 19 | 20 | stack createEmptyStack(int len) { 21 | stack s = malloc(sizeof(struct StackRecord)); 22 | s->array = malloc(sizeof(char) * len); 23 | s->top = -1; 24 | return s; 25 | } 26 | 27 | void freeStack(stack s) { 28 | free(s->array); 29 | free(s); 30 | } 31 | 32 | void push(stack s, char v) { 33 | s->array[++s->top] = v; 34 | } 35 | 36 | char pop(stack s) { 37 | assert(s->top > -1); 38 | return s->array[s->top--]; 39 | } 40 | 41 | bool isEmpty(stack s) { 42 | return s->top == -1; 43 | } 44 | 45 | bool isValid(char* s) { 46 | bool rt = true; 47 | stack stack = createEmptyStack(strlen(s)); 48 | while (*s) { 49 | if (*s == '(') push(stack, ')'); 50 | else if (*s == '{') push(stack, '}'); 51 | else if (*s == '[') push(stack, ']'); 52 | else { 53 | if (isEmpty(stack) || pop(stack) != *s) { 54 | rt = false; 55 | break; 56 | } 57 | } 58 | s++; 59 | } 60 | 61 | if (rt) rt = isEmpty(stack); 62 | freeStack(stack); 63 | return rt; 64 | } 65 | 66 | void test(bool expect, char* s) { 67 | EXPECT_EQ_INT(expect, isValid(s)); 68 | } 69 | 70 | int main(void) { 71 | test(true, "()"); 72 | test(true, "(){}[]"); 73 | 74 | test(false, "(]"); 75 | test(false, "([)]"); 76 | test(false, "["); 77 | 78 | return testOutput(); 79 | } 80 | -------------------------------------------------------------------------------- /c/000-099/79-word-search.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 基本的深度优先搜索解法 6 | * 讨论区学到的小技巧: a ^ x ^ x = a 7 | */ 8 | 9 | #include 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | bool search(char **board, int boardRowSize, int boardColSize, int i, int j, char *word) { 14 | if (*word == '\0') return true; 15 | if (i < 0 || i >= boardRowSize || j < 0 || j >= boardColSize) return false; 16 | if (board[i][j] != *word) return false; 17 | board[i][j] ^= 0xFF; 18 | bool exist = 19 | search(board, boardRowSize, boardColSize, i + 1, j, word + 1) || 20 | search(board, boardRowSize, boardColSize, i - 1, j, word + 1) || 21 | search(board, boardRowSize, boardColSize, i, j + 1, word + 1) || 22 | search(board, boardRowSize, boardColSize, i, j - 1, word + 1); 23 | board[i][j] ^= 0xFF; 24 | return exist; 25 | } 26 | 27 | bool exist(char **board, int boardRowSize, int boardColSize, char *word) { 28 | for (int i = 0; i < boardRowSize; ++i) 29 | for (int j = 0; j < boardColSize; ++j) 30 | if (search(board, boardRowSize, boardColSize, i, j, word)) 31 | return true; 32 | 33 | return false; 34 | } 35 | 36 | void test(const char *board, bool expect, char *word) { 37 | arrayEntry *e = arrayParse2D(board, ARRAY_CHAR); 38 | 39 | EXPECT_EQ_INT(expect, exist(arrayValue(e), arrayRow(e), arrayCol(e), word)); 40 | 41 | arrayFree(e); 42 | } 43 | 44 | int main(void) { 45 | const char *board = 46 | "[" 47 | "[A,B,C,E]," 48 | "[S,F,C,S]," 49 | "[A,D,E,E]" 50 | "]"; 51 | test(board, true, "ABCCED"); 52 | test(board, true, "SEE"); 53 | test(board, false, "ABCB"); 54 | 55 | return testOutput(); 56 | } 57 | -------------------------------------------------------------------------------- /c/800-899/838-push-dominoes.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 两个指针, 模拟实际操作过程即可 6 | * 第一次提交的时候, 没有考虑到这个情况: ".L.R." 7 | */ 8 | 9 | #include 10 | #include "c/test.h" 11 | 12 | char *pushDominoes(char *dominoes) { 13 | int slow = 0, fast = 0; 14 | 15 | for (; dominoes[fast] != '\0'; fast++) { 16 | if (dominoes[fast] == 'L') { 17 | if (dominoes[slow] == 'L' || dominoes[slow] == '.') { 18 | // all set 'L' 19 | while (slow < fast) dominoes[slow++] = 'L'; 20 | } else { 21 | // 此时是R, 向中间靠拢 22 | int mid = (fast + slow) / 2; 23 | bool even = (fast + slow) % 2 == 0; 24 | while (slow < mid) dominoes[slow++] = 'R'; 25 | 26 | if (even) 27 | slow++; 28 | else 29 | dominoes[slow++] = 'R'; 30 | 31 | while (slow < fast) dominoes[slow++] = 'L'; 32 | } 33 | } else if (dominoes[fast] == 'R') { 34 | if (dominoes[slow] == 'L' || dominoes[slow] == '.') { 35 | // 忽略 36 | slow = fast; 37 | } else { 38 | // all set 'R' 39 | while (slow < fast) dominoes[slow++] = 'R'; 40 | } 41 | } 42 | } 43 | 44 | // 注意, 如何最后一次操作是‘R’, 要把后面都推倒 45 | if (dominoes[slow] == 'R') { 46 | while (slow < fast) dominoes[slow++] = 'R'; 47 | } 48 | 49 | return dominoes; 50 | } 51 | 52 | void test(const char *expect, const char *dominoes) { 53 | int len = strlen(dominoes) + 1; 54 | char *str = malloc(sizeof(char) * len); 55 | memcpy(str, dominoes, len); 56 | 57 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, pushDominoes(str)); 58 | } 59 | 60 | int main(void) { 61 | test("RR.L", "RR.L"); 62 | test("LL.RR.LLRRLL..", ".L.R...LR..L.."); 63 | 64 | test("LL.RR", ".L.R."); 65 | 66 | return testOutput(); 67 | } 68 | -------------------------------------------------------------------------------- /c/000-099/46-permutations.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 全排列的递归解法, 依次交换数据 6 | */ 7 | 8 | #include /* malloc() */ 9 | #include /* memcpy() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | int factorial(int n) { 14 | if (n <= 1) return 1; 15 | return n * factorial(n - 1); 16 | } 17 | 18 | void swap(int *a, int *b) { 19 | int tmp = *a; 20 | *a = *b; 21 | *b = tmp; 22 | } 23 | 24 | void permutations(int **rt, int *rtSize, int *nums, int start, int length) { 25 | if (start == length - 1) { 26 | memcpy(rt[(*rtSize)++] = malloc(sizeof(int) * length), nums, sizeof(int) * length); 27 | } else { 28 | for (int i = start; i != length; i++) { 29 | swap(&nums[start], &nums[i]); 30 | permutations(rt, rtSize, nums, start+1, length); 31 | swap(&nums[start], &nums[i]); /* 没有这一行也是正确的, 有了这一行是为了生成的数据是按照书写顺序 */ 32 | } 33 | } 34 | } 35 | 36 | /** 37 | * Return an array of arrays of size *returnSize. 38 | * Note: The returned array must be malloced, assume caller calls free(). 39 | */ 40 | int **permute(int *nums, int numsSize, int *returnSize) { 41 | int **rt = malloc(sizeof(int*) * factorial(numsSize)); 42 | *returnSize = 0; 43 | 44 | permutations(rt, returnSize, nums, 0, numsSize); 45 | return rt; 46 | } 47 | 48 | void test(const char* expect, const char* str) { 49 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 50 | int returnSize; 51 | int **a = permute(arrayValue(e), arraySize(e), &returnSize); 52 | 53 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString2DSameCol(a, returnSize, arraySize(e), ARRAY_INT)); 54 | 55 | arrayFree(e); 56 | } 57 | 58 | int main(void) { 59 | test("[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,2,1],[3,1,2]]", "[1,2,3]"); 60 | 61 | return testOutput(); 62 | } 63 | -------------------------------------------------------------------------------- /c/000-099/78-subsets.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 先初始化一个空的子集, 然后将每个元素依次放入之前的每个子集的后面 6 | */ 7 | 8 | #include /* pow() */ 9 | #include /* malloc() */ 10 | #include /* memcpy() */ 11 | #include "c/data-structures/array.h" 12 | #include "c/test.h" 13 | 14 | /** 15 | * Return an array of arrays of size *returnSize. 16 | * The sizes of the arrays are returned as *columnSizes array. 17 | * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free(). 18 | */ 19 | int **subsets(int *nums, int numsSize, int **columnSizes, int *returnSize) { 20 | *returnSize = pow(2, numsSize); 21 | int **rtn = malloc(sizeof(int*) * *returnSize); 22 | *columnSizes = malloc(sizeof(int) * *returnSize); 23 | 24 | int rtnSize = 1; 25 | rtn[0] = NULL; 26 | (*columnSizes)[0] = 0; 27 | 28 | for (int i = 0; i < numsSize; ++i) { 29 | for (int j = 0; j < rtnSize; ++j) { 30 | int newIndex = rtnSize + j; 31 | rtn[newIndex] = malloc(sizeof(int) * ((*columnSizes)[newIndex] = (*columnSizes)[j] + 1)); 32 | memcpy(rtn[newIndex], rtn[j], sizeof(int) * (*columnSizes)[j]); 33 | rtn[newIndex][(*columnSizes)[j]] = nums[i]; 34 | } 35 | rtnSize *= 2; 36 | } 37 | 38 | return rtn; 39 | } 40 | 41 | void test(const char* expect, const char* str) { 42 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 43 | int *columnSizes; 44 | int returnSize; 45 | int **a = subsets(arrayValue(e), arraySize(e), &columnSizes, &returnSize); 46 | 47 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString2D(a, returnSize, columnSizes, ARRAY_INT)); 48 | 49 | arrayFree(e); 50 | } 51 | 52 | int main(void) { 53 | test("[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]", 54 | "[1,2,3]"); 55 | 56 | return testOutput(); 57 | } 58 | -------------------------------------------------------------------------------- /c/1400-1499/1410-html-entity-parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 字符串的批量替换问题. 6 | * 性能不是最优, 但代码还是很简单的. 7 | * 定义一个全局变量的替换字符的数组, 遍历即可. 8 | */ 9 | 10 | #include /* malloc() */ 11 | #include /* strlen(), strncmp() */ 12 | #include "c/test.h" 13 | 14 | struct character { 15 | char symbol; 16 | char *entry; 17 | int entryLen; 18 | }; 19 | 20 | int N = 6; 21 | struct character characters[] = { 22 | {'"', """, 6}, 23 | {'\'', "'", 6}, 24 | {'&', "&", 5}, 25 | {'>', ">", 4}, 26 | {'<', "<", 4}, 27 | {'/', "⁄", 7}}; 28 | 29 | char *entityParser(char *text) { 30 | int i, len = strlen(text); 31 | char *rtn = malloc(sizeof(char) * (len + 1)); 32 | char *p1 = text, *p2 = rtn; 33 | 34 | while (*p1 != '\0') { 35 | if (*p1 == '&') { 36 | for (i = 0; i < N; i++) { 37 | struct character c = characters[i]; 38 | if (strncmp(c.entry, p1, c.entryLen) == 0) { 39 | p1 += c.entryLen; 40 | *p2++ = c.symbol; 41 | break; 42 | } 43 | } 44 | if (i < N) continue; 45 | } 46 | *p2++ = *p1++; 47 | } 48 | *p2 = '\0'; 49 | return rtn; 50 | } 51 | 52 | void test(const char *expect, char *text) { 53 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, entityParser(text)); 54 | } 55 | 56 | int main(void) { 57 | test("& is an HTML entity but &ambassador; is not.", "& is an HTML entity but &ambassador; is not."); 58 | test("and I quote: \"...\"", "and I quote: "...""); 59 | test("Stay home! Practice on Leetcode :)", "Stay home! Practice on Leetcode :)"); 60 | test("x > y && x < y is always false", "x > y && x < y is always false"); 61 | test("leetcode.com/problemset/all", "leetcode.com⁄problemset⁄all"); 62 | return testOutput(); 63 | } 64 | -------------------------------------------------------------------------------- /c/300-399/377-combination-sum-iv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * v1: 第一次尝试用递归, 结果超时, 于是在递归的基础上, 缓存中间变量 6 | * v2: 动态规划 (打印递归结果, 就很容易看出如何写) 7 | */ 8 | 9 | #include /* malloc(), free() */ 10 | #include /* memset() */ 11 | #include "c/data-structures/array.h" 12 | #include "c/test.h" 13 | 14 | int loop(int *nums, int numsSize, int target, int *tmp) { 15 | if (tmp[target] != -1) 16 | return tmp[target]; 17 | 18 | int rtn = 0; 19 | for (int i = 0; i < numsSize; ++i) 20 | if (target >= nums[i]) 21 | rtn += loop(nums, numsSize, target - nums[i], tmp); 22 | tmp[target] = rtn; 23 | return rtn; 24 | } 25 | 26 | int combinationSum4_v1(int *nums, int numsSize, int target) { 27 | int *tmp = malloc(sizeof(int) * (target + 1)); 28 | tmp[0] = 1; 29 | for (int i = 1; i <= target; ++i) 30 | tmp[i] = -1; 31 | int rtn = loop(nums, numsSize, target, tmp); 32 | free(tmp); 33 | return rtn; 34 | } 35 | 36 | int combinationSum4_v2(int *nums, int numsSize, int target) { 37 | int *tmp = malloc(sizeof(int) * (target + 1)); 38 | memset(tmp, 0, sizeof(int) * (target + 1)); 39 | tmp[0] = 1; 40 | for (int i = 1; i <= target; ++i) 41 | for (int j = 0; j < numsSize; ++j) 42 | if (i >= nums[j]) 43 | tmp[i] += tmp[i - nums[j]]; 44 | int rtn = tmp[target]; 45 | free(tmp); 46 | return rtn; 47 | } 48 | 49 | void test(int expect, const char *str, int target) { 50 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 51 | 52 | EXPECT_EQ_INT(expect, combinationSum4_v1(arrayValue(e), arraySize(e), target)); 53 | EXPECT_EQ_INT(expect, combinationSum4_v2(arrayValue(e), arraySize(e), target)); 54 | 55 | arrayFree(e); 56 | } 57 | 58 | int main(void) { 59 | test(7, "[1, 2, 3]", 4); 60 | test(181997601, "[1, 2, 3]", 32); 61 | 62 | return testOutput(); 63 | } 64 | -------------------------------------------------------------------------------- /c/000/leftmost-column-with-at-least-a-one.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 由于每一行都是有序的, 所以可以从右下角往左上角查找 6 | */ 7 | 8 | #include /* malloc(), free() */ 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | 12 | struct BinaryMatrix { 13 | arrayEntry *e; 14 | int (*get)(struct BinaryMatrix *, int, int); 15 | int *(*dimensions)(struct BinaryMatrix *); 16 | }; 17 | 18 | int get(struct BinaryMatrix *matrix, int x, int y) { 19 | return ((int **)arrayValue(matrix->e))[x][y]; 20 | } 21 | 22 | int *dimensitons(struct BinaryMatrix *matrix) { 23 | int *dimensitons = malloc(sizeof(int) * 2); 24 | dimensitons[0] = arrayRow(matrix->e); 25 | dimensitons[1] = arrayCol(matrix->e); 26 | return dimensitons; 27 | } 28 | 29 | /** 30 | * // This is the BinaryMatrix's API interface. 31 | * // You should not implement it, or speculate about its implementation 32 | * struct BinaryMatrix { 33 | * int (*get)(struct BinaryMatrix*, int, int); 34 | * int* (*dimensions)(struct BinaryMatrix*); 35 | * }; 36 | */ 37 | int leftMostColumnWithOne(struct BinaryMatrix *matrix) { 38 | int *dimensitons = matrix->dimensions(matrix); 39 | int x = dimensitons[0] - 1, y = dimensitons[1] - 1, y1 = y; 40 | free(dimensitons); 41 | while (x >= 0 && y >= 0) { 42 | matrix->get(matrix, x, y) == 0 ? --x : --y; 43 | } 44 | return x == -1 && y == y1 ? -1 : y + 1; 45 | } 46 | 47 | void test(int expect, char *s) { 48 | arrayEntry *e = arrayParse2D(s, ARRAY_INT); 49 | struct BinaryMatrix matrix = {e, get, dimensitons}; 50 | EXPECT_EQ_INT(expect, leftMostColumnWithOne(&matrix)); 51 | arrayFree(e); 52 | } 53 | 54 | int main(void) { 55 | test(0, "[[0,0],[1,1]]"); 56 | test(1, "[[0,0],[0,1]]"); 57 | test(-1, "[[0,0],[0,0]]"); 58 | test(1, "[[0,0,0,1],[0,0,1,1],[0,1,1,1]]"); 59 | 60 | return testOutput(); 61 | } 62 | -------------------------------------------------------------------------------- /c/200-299/216-combination-sum-iii.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 跟前系列的思路一样 6 | */ 7 | 8 | #include /* malloc(), free() */ 9 | #include /* memcpy() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | #define MAX_SIZE 100 14 | 15 | void dfs(int *nums, int numsSize, int start, int k, int n, int ***rtn, int **columnSizes, int *returnSize) { 16 | if (numsSize >= k) { 17 | if (n == 0) { 18 | (*columnSizes)[*returnSize] = k; 19 | memcpy(((*rtn)[*returnSize] = malloc(sizeof(int *) * k)), nums, sizeof(int) * k); 20 | (*returnSize)++; 21 | } 22 | return; 23 | } 24 | 25 | for (int i = start; i < 10; ++i) { 26 | if (n - i < 0) 27 | return; 28 | nums[numsSize] = i; 29 | dfs(nums, numsSize + 1, i + 1, k, n - i, rtn, columnSizes, returnSize); 30 | } 31 | } 32 | 33 | /** 34 | * Return an array of arrays of size *returnSize. 35 | * The sizes of the arrays are returned as *columnSizes array. 36 | * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free(). 37 | */ 38 | int **combinationSum3(int k, int n, int **columnSizes, int *returnSize) { 39 | *returnSize = 0; 40 | int **rtn = malloc(sizeof(int *) * MAX_SIZE); 41 | *columnSizes = malloc(sizeof(int) * MAX_SIZE); 42 | int *nums = malloc(sizeof(int) * k); 43 | dfs(nums, 0, 1, k, n, &rtn, columnSizes, returnSize); 44 | free(nums); 45 | return rtn; 46 | } 47 | 48 | void test(const char *expect, int k, int n) { 49 | int *columnSizes; 50 | int returnSize; 51 | int **a = combinationSum3(k, n, &columnSizes, &returnSize); 52 | 53 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString2D(a, returnSize, columnSizes, ARRAY_INT)); 54 | } 55 | 56 | int main(void) { 57 | test("[[1,2,4]]", 3, 7); 58 | test("[[1,2,6],[1,3,5],[2,3,4]]", 3, 9); 59 | test("[]", 2, 18); 60 | 61 | return testOutput(); 62 | } 63 | -------------------------------------------------------------------------------- /c/000-099/33-search-in-rotated-sorted-array.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * https://leetcode.com/problems/search-in-rotated-sorted-array/ 6 | * Q: 在一个循环有序数组中(想象一个循环链表, 但起始位置可能不在数组头部), O(log n)的时间复杂度找到一个元素的位置 7 | * 8 | * 看到题目, 就是要实现一个升级版本的二分查找, 接下来就要考虑如何计算 low 和 high 9 | * 第1步: 判断哪边是有序的 10 | * 第2步: 找出异常情况: 要找的值在边界之外 11 | * 12 | * 修改记录: 13 | * 2022-03-28: 今天才发现, 之前没按规则实现, 于是重写了 14 | * 2017-08-25: 按照顺序查找实现的, 虽然AC并且耗时也是第一梯队的, 但代码不符合规则 15 | */ 16 | 17 | #include "c/data-structures/array.h" 18 | #include "c/test.h" 19 | 20 | int search(int *nums, int numsSize, int target) { 21 | int low = 0, high = numsSize - 1, mid; 22 | while (low <= high) { 23 | mid = (low + high) / 2; 24 | if (nums[mid] == target) 25 | return mid; 26 | 27 | if (nums[low] <= nums[mid]) { // 左侧有序 28 | if (nums[mid] > target) { // 可能在左边 29 | // 但特殊情况在右边 30 | if (nums[low] > target) 31 | low = mid + 1; 32 | else 33 | high = mid - 1; 34 | } else { 35 | low = mid + 1; 36 | } 37 | } else { // 右侧有序 38 | if (nums[mid] < target) { // 可能在右边 39 | // 但特殊情况在左边 40 | if (nums[high] < target) 41 | high = mid - 1; 42 | else 43 | low = mid + 1; 44 | } else { 45 | high = mid - 1; 46 | } 47 | } 48 | } 49 | return -1; 50 | } 51 | 52 | void test(int expect, const char *nums, int target) { 53 | arrayEntry *e = arrayParse1D(nums, ARRAY_INT); 54 | 55 | EXPECT_EQ_INT(expect, search(arrayValue(e), arraySize(e), target)); 56 | 57 | arrayFree(e); 58 | } 59 | 60 | int main(void) { 61 | test(4, "[4,5,6,7,0,1,2]", 0); 62 | test(-1, "[4,5,6,7,0,1,2]", 3); 63 | test(-1, "[1]", 0); 64 | 65 | // 以下是提交错误时的测试用例 66 | test(0, "[3,5,1]", 3); 67 | test(2, "[5,1,3]", 3); 68 | test(0, "[5,1,3]", 5); 69 | test(4, "[4,5,6,7,8,1,2,3]", 8); 70 | test(1, "[3,1]", 1); 71 | 72 | return testOutput(); 73 | } 74 | -------------------------------------------------------------------------------- /c/000-099/54-spiral-matrix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 设置好边界, 循环画4条线, 从左到右, 从上到下, 从右到左, 从下到上. 6 | * 结束循环的条件, 通过数组长度判断比较简单. 7 | */ 8 | 9 | #include /* malloc() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | int *spiralOrder(int **matrix, int matrixSize, int *matrixColSize, int *returnSize) { 14 | if (matrixSize == 0) { 15 | *returnSize = 0; 16 | return NULL; 17 | } 18 | 19 | *returnSize = matrixSize * matrixColSize[0]; 20 | int *arr = malloc(sizeof(int) * *returnSize); 21 | int size = 0; 22 | int r1 = 0, r2 = matrixSize - 1, c1 = 0, c2 = matrixColSize[0] - 1; 23 | 24 | while (1) { 25 | // left -> right 26 | for (int i = c1; i <= c2; i++) { 27 | arr[size++] = matrix[r1][i]; 28 | } 29 | if (size == *returnSize) break; 30 | r1++; 31 | 32 | // up -> down 33 | for (int i = r1; i <= r2; i++) { 34 | arr[size++] = matrix[i][c2]; 35 | } 36 | if (size == *returnSize) break; 37 | c2--; 38 | 39 | // right -> left 40 | for (int i = c2; i >= c1; i--) { 41 | arr[size++] = matrix[r2][i]; 42 | } 43 | if (size == *returnSize) break; 44 | r2--; 45 | 46 | // down -> up 47 | for (int i = r2; i >= r1; i--) { 48 | arr[size++] = matrix[i][c1]; 49 | } 50 | if (size == *returnSize) break; 51 | c1++; 52 | } 53 | 54 | return arr; 55 | } 56 | 57 | void test(const char *expect, char *s) { 58 | arrayEntry *e = arrayParse2D(s, ARRAY_INT); 59 | 60 | int returnSize; 61 | int *arr = spiralOrder(arrayValue(e), arrayRow(e), arrayCols(e), &returnSize); 62 | 63 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString1D(arr, returnSize, ARRAY_INT)); 64 | 65 | arrayFree(e); 66 | } 67 | 68 | int main(void) { 69 | test("[1,2,3,6,9,8,7,4,5]", "[[1,2,3],[4,5,6],[7,8,9]]"); 70 | test("[1,2,3,4,8,12,11,10,9,5,6,7]", "[[1,2,3,4],[5,6,7,8],[9,10,11,12]]"); 71 | 72 | return testOutput(); 73 | } 74 | -------------------------------------------------------------------------------- /c/000-099/94-binary-tree-inorder-traversal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 维护一个栈, 模拟递归行为, 具体见代码 6 | */ 7 | 8 | #include 9 | #include 10 | #include "c/data-structures/array.h" 11 | #include "c/data-structures/binary-tree.h" 12 | #include "c/test.h" 13 | 14 | #define MAX_SIZE 1000 /* 题目没有给出最大数量, 假设1000 */ 15 | struct stack { 16 | struct TreeNode *arr[MAX_SIZE]; 17 | int size; 18 | }; 19 | 20 | bool isEmpty(struct stack *s) { 21 | return s->size == 0; 22 | } 23 | 24 | void push(struct stack *s, struct TreeNode *node) { 25 | s->arr[s->size++] = node; 26 | } 27 | 28 | struct TreeNode *pop(struct stack *s) { 29 | if (s->size == 0) return NULL; 30 | return s->arr[--s->size]; 31 | } 32 | 33 | /** 34 | * Definition for a binary tree node. 35 | * struct TreeNode { 36 | * int val; 37 | * struct TreeNode *left; 38 | * struct TreeNode *right; 39 | * }; 40 | */ 41 | /** 42 | * Return an array of size *returnSize. 43 | * Note: The returned array must be malloced, assume caller calls free(). 44 | */ 45 | int *inorderTraversal(struct TreeNode *root, int *returnSize) { 46 | int *rtn = malloc(sizeof(int) * MAX_SIZE); 47 | *returnSize = 0; 48 | 49 | struct stack s = {}; 50 | struct TreeNode *cur = root; 51 | 52 | while (cur != NULL || !isEmpty(&s)) { 53 | while (cur != NULL) { 54 | push(&s, cur); 55 | cur = cur->left; 56 | } 57 | 58 | cur = pop(&s); 59 | rtn[(*returnSize)++] = cur->val; 60 | cur = cur->right; 61 | } 62 | 63 | return rtn; 64 | } 65 | 66 | void test(const char *expect, const char *s) { 67 | struct TreeNode *root = treeParse(s); 68 | int returnSize; 69 | int *rtn = inorderTraversal(root, &returnSize); 70 | 71 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString1D(rtn, returnSize, ARRAY_INT)); 72 | 73 | treeFree(root); 74 | } 75 | 76 | int main(void) { 77 | test("[1,3,2]", "[1,null,2,3]"); 78 | 79 | return testOutput(); 80 | } 81 | -------------------------------------------------------------------------------- /c/900-999/985-sum-of-even-numbers-after-queries.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 中等难度的题? 其实很简单 6 | * 维护一个sum变量, 再循环计算一次即可 7 | */ 8 | 9 | #include 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | /** 14 | * Note: The returned array must be malloced, assume caller calls free(). 15 | */ 16 | int *sumEvenAfterQueries(int *nums, int numsSize, int **queries, int queriesSize, int *queriesColSize, int *returnSize) { 17 | *returnSize = 0; 18 | int *returnArray = malloc(sizeof(int) * queriesSize); 19 | 20 | int sum = 0; 21 | for (int i = 0; i < numsSize; i++) { 22 | if (nums[i] % 2 == 0) 23 | sum += nums[i]; 24 | } 25 | 26 | int v1, v2; 27 | bool even1, even2; 28 | for (int i = 0; i < queriesSize; i++) { 29 | v1 = nums[queries[i][1]]; 30 | v2 = queries[i][0]; 31 | even1 = v1 % 2 == 0; 32 | even2 = v2 % 2 == 0; 33 | 34 | if (even1) { 35 | if (even2) { 36 | sum += v2; // 偶, 偶: sum + 第二个数 37 | } else { 38 | sum -= v1; // 偶, 奇: sum - 第一个数 39 | } 40 | } else { 41 | if (!even2) { 42 | sum += v1 + v2; // 奇, 奇: sum + 第一个数 + 第二个数 43 | } 44 | } 45 | 46 | nums[queries[i][1]] += v2; 47 | returnArray[(*returnSize)++] = sum; 48 | } 49 | 50 | return returnArray; 51 | } 52 | 53 | void test(const char *expect, const char *nums, const char *queries) { 54 | arrayEntry *e1 = arrayParse1D(nums, ARRAY_INT); 55 | arrayEntry *e2 = arrayParse2D(queries, ARRAY_INT); 56 | 57 | int returnSize; 58 | int *returnArray = sumEvenAfterQueries(arrayValue(e1), arraySize(e1), arrayValue(e2), 59 | arrayRow(e2), arrayCols(e2), &returnSize); 60 | 61 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString1D(returnArray, returnSize, ARRAY_INT)); 62 | 63 | arrayFree(e2); 64 | arrayFree(e1); 65 | } 66 | 67 | int main(void) { 68 | test("[8,6,2,4]", "[1,2,3,4]", "[[1,0],[-3,1],[-4,0],[2,3]]"); 69 | 70 | return testOutput(); 71 | } 72 | -------------------------------------------------------------------------------- /c/800-899/885-spiral-matrix-iii.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 先向右, 开始按照螺旋划线. 6 | * 注意每画两个方向后, 数量+1. 7 | */ 8 | 9 | #include /* malloc() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | 13 | int **spiralMatrixIII(int R, int C, int r0, int c0, int *returnSize, int **returnColumnSizes) { 14 | *returnSize = R * C; 15 | if (*returnSize == 0) { 16 | *returnColumnSizes = NULL; 17 | return NULL; 18 | } 19 | int **matrix = malloc(sizeof(int*) * *returnSize); 20 | *returnColumnSizes = malloc(sizeof(int) * *returnSize); 21 | for (int i = 0; i < *returnSize; ++i) { 22 | (*returnColumnSizes)[i] = 2; 23 | matrix[i] = malloc(sizeof(int) * 2); 24 | } 25 | 26 | int cur = 0, loop = 0, dir; 27 | matrix[cur][0] = r0; 28 | matrix[cur++][1] = c0; 29 | while (cur < *returnSize) { 30 | dir = loop % 4; /* 0: right, 1: down, 2: left, 3: up */ 31 | for (int i = 0; i < loop / 2 + 1; ++i) { /* 每两次升级画线的长度 */ 32 | switch (dir) { 33 | case 0: ++c0; break; 34 | case 1: ++r0; break; 35 | case 2: --c0; break; 36 | case 3: --r0; break; 37 | } 38 | 39 | if (r0 >= 0 && r0 < R && c0 >= 0 && c0 < C) { /* 合法的值才放入 */ 40 | matrix[cur][0] = r0; 41 | matrix[cur++][1] = c0; 42 | } 43 | } 44 | ++loop; 45 | } 46 | 47 | return matrix; 48 | } 49 | 50 | void test(const char *expect, int R, int C, int r0, int c0) { 51 | int returnSize; 52 | int *returnColumnSizes; 53 | int **matrix = spiralMatrixIII(R, C, r0, c0, &returnSize, &returnColumnSizes); 54 | 55 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString2D(matrix, returnSize, returnColumnSizes, ARRAY_INT)); 56 | } 57 | 58 | int main(void) { 59 | test("[[0,0],[0,1],[0,2],[0,3]]", 1, 4, 0, 0); 60 | test("[[1,4],[1,5],[2,5],[2,4],[2,3],[1,3],[0,3],[0,4],[0,5],[3,5],[3,4],[3,3],[3,2],[2,2],[1,2],[0,2],[4,5],[4,4],[4,3],[4,2],[4,1],[3,1],[2,1],[1,1],[0,1],[4,0],[3,0],[2,0],[1,0],[0,0]]", 5, 6, 1, 4); 61 | 62 | return testOutput(); 63 | } 64 | -------------------------------------------------------------------------------- /c/000-099/32-longest-valid-parentheses.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 记录括号的索引到栈中, 同时弹出合法的括号索引. 6 | * 最后栈内都是非法括号的索引, 此时连续索引之间最大的差值就是答案. 7 | */ 8 | 9 | #include /* assert() */ 10 | #include 11 | #include /* malloc(), free() */ 12 | #include /* strlen() */ 13 | #include "c/test.h" 14 | 15 | struct StackRecord{ 16 | int top; 17 | int *array; 18 | }; 19 | typedef struct StackRecord * stack; 20 | 21 | stack createEmptyStack(int len) { 22 | stack s = malloc(sizeof(struct StackRecord)); 23 | s->array = malloc(sizeof(int) * len); 24 | s->top = -1; 25 | return s; 26 | } 27 | 28 | void freeStack(stack s) { 29 | free(s->array); 30 | free(s); 31 | } 32 | 33 | void push(stack s, int v) { 34 | s->array[++s->top] = v; 35 | } 36 | 37 | int pop(stack s) { 38 | assert(s->top > -1); 39 | return s->array[s->top--]; 40 | } 41 | 42 | bool isEmpty(stack s) { 43 | return s->top == -1; 44 | } 45 | 46 | int top(stack s) { 47 | return s->array[s->top]; 48 | } 49 | 50 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 51 | int longestValidParentheses(char* s) { 52 | int len = strlen(s); 53 | 54 | stack stack = createEmptyStack(len); 55 | for (int i = 0; i < len; i++) { 56 | if (s[i] == '(') { 57 | push(stack, i); 58 | } else { 59 | if (!isEmpty(stack) && s[top(stack)] == '(') pop(stack); 60 | else push(stack, i); 61 | } 62 | } 63 | int longest = 0; 64 | if (isEmpty(stack)) { 65 | longest = len; 66 | } else { 67 | int a = len, b; 68 | while (!isEmpty(stack)) { 69 | b = pop(stack); 70 | longest = MAX(longest, a-b-1); 71 | a = b; 72 | } 73 | longest = MAX(longest, a); 74 | } 75 | freeStack(stack); 76 | return longest; 77 | } 78 | 79 | void test(int expect, char* s) { 80 | EXPECT_EQ_INT(expect, longestValidParentheses(s)); 81 | } 82 | 83 | int main(void) { 84 | test(2, "(()"); 85 | test(4, ")()())"); 86 | test(2, "()(()"); 87 | test(2, "(()(((()"); 88 | 89 | return testOutput(); 90 | } 91 | -------------------------------------------------------------------------------- /c/100-199/102-binary-tree-level-order-traversal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 提前分配好空间, 然后遍历树即可 6 | */ 7 | 8 | #include /* pow() */ 9 | #include /* malloc() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/data-structures/binary-tree.h" 12 | #include "c/test.h" 13 | 14 | 15 | /** 16 | * Definition for a binary tree node. 17 | * struct TreeNode { 18 | * int val; 19 | * struct TreeNode *left; 20 | * struct TreeNode *right; 21 | * }; 22 | */ 23 | 24 | void dfs(int ***rtn, int **columnSizes, struct TreeNode *root, int index) { 25 | if (root == NULL) return; 26 | (*rtn)[index][(*columnSizes)[index]++] = root->val; 27 | dfs(rtn, columnSizes, root->left, index+1); 28 | dfs(rtn, columnSizes, root->right, index+1); 29 | } 30 | 31 | /** 32 | * Return an array of arrays of size *returnSize. 33 | * The sizes of the arrays are returned as *columnSizes array. 34 | * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free(). 35 | */ 36 | int **levelOrder(struct TreeNode *root, int **columnSizes, int *returnSize) { 37 | *returnSize = treeHeight(root); 38 | if (*returnSize <= 0) return NULL; 39 | 40 | // initialize 41 | int **rtn = malloc(sizeof(int *) * *returnSize); 42 | *columnSizes = malloc(sizeof(int) * *returnSize); 43 | for (int i = 0; i < *returnSize; ++i) { 44 | rtn[i] = malloc(sizeof(int) * pow(2, i < 8 ? i : 8)); /* 防止树的高度过大 */ 45 | (*columnSizes)[i] = 0; 46 | } 47 | 48 | dfs(&rtn, columnSizes, root, 0); 49 | return rtn; 50 | } 51 | 52 | void test(const char *expect, const char *s) { 53 | struct TreeNode* tree = treeParse(s); 54 | int *columnSizes; 55 | int returnSize; 56 | int** rtn = levelOrder(tree, &columnSizes, &returnSize); 57 | 58 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString2D(rtn, returnSize, columnSizes, ARRAY_INT)); 59 | 60 | treeFree(tree); 61 | } 62 | 63 | int main(void) { 64 | test("[[3],[9,20],[15,7]]", "[3,9,20,null,null,15,7]"); 65 | 66 | return testOutput(); 67 | } 68 | -------------------------------------------------------------------------------- /c/000-099/45-jump-game-ii.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * v1: 先想到的是动态规划, 结果超时. 6 | * 7 | * v2: 调整思路后, 发现了这个解法, 标记一个最小步数的最远距离, 依次直到抵达数组的最后. 详见下表 8 | * 9 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 <- 数组下标 10 | * 7 0 9 6 9 6 1 7 9 0 1 2 9 0 3 <- 数组内容 11 | * step1. + 1 1 1 1 1 1 1 12 | * step2. + 2 2 2 2 13 | * step3. + 2 2 14 | * step4. + 2 <- 结果 15 | */ 16 | 17 | #include /* memset() */ 18 | #include "c/data-structures/array.h" 19 | #include "c/test.h" 20 | 21 | /* Time Limit Exceeded */ 22 | int jump_v1(int *nums, int numsSize) { 23 | int table[numsSize]; 24 | memset(table, 0, sizeof(table)); 25 | 26 | for (int i = 0; i < numsSize - 1; i++) { 27 | for (int j = 1; j <= nums[i]; j++) { 28 | if (i + j >= numsSize) 29 | break; 30 | if (table[i + j] == 0 || table[i + j] > table[i] + 1) 31 | table[i + j] = table[i] + 1; 32 | } 33 | } 34 | 35 | return table[numsSize - 1]; 36 | } 37 | 38 | int jump_v2(int *nums, int numsSize) { 39 | int table[numsSize]; 40 | memset(table, 0, sizeof(table)); 41 | 42 | int curIndex = 0; 43 | for (int i = 0; i < numsSize-1; i++) { 44 | if (curIndex > i + nums[i]) { 45 | continue; 46 | } 47 | int j = curIndex + 1; 48 | curIndex = i + nums[i]; 49 | while (j <= curIndex) { 50 | if (j == numsSize - 1) { 51 | return table[i] + 1; 52 | } 53 | table[j++] = table[i] + 1; 54 | } 55 | } 56 | 57 | return table[numsSize - 1]; 58 | } 59 | 60 | void test(int expect, char *s) { 61 | arrayEntry *e = arrayParse1D(s, ARRAY_INT); 62 | 63 | EXPECT_EQ_INT(expect, jump_v1(arrayValue(e), arraySize(e))); 64 | 65 | EXPECT_EQ_INT(expect, jump_v2(arrayValue(e), arraySize(e))); 66 | 67 | arrayFree(e); 68 | } 69 | 70 | int main(void) { 71 | test(2, "[2,3,1,1,4]"); 72 | 73 | test(0, "[0]"); 74 | test(0, "[1]"); 75 | test(1, "[2, 3, 1]"); 76 | test(2, "[7,0,9,6,9,6,1,7,9,0,1,2,9,0,3]"); 77 | 78 | return testOutput(); 79 | } 80 | -------------------------------------------------------------------------------- /c/1700-1799/1770-maximum-score-from-performing-multiplication-operations_MLE_TLE.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 一看这是一个动态规划的问题, 分析后发现需要画一个二叉树的表格? 6 | * 头一次遇到这样的问题, 兴奋极了, 一顿操作下来 7 | * 又是 Memory Limit Exceeded, 又是 Time Limit Exceeded 的 8 | * 9 | * 下个文件再从头开始... 10 | */ 11 | 12 | #include 13 | #include "c/data-structures/array.h" 14 | #include "c/test.h" 15 | 16 | struct Cell { 17 | int v; // value 18 | int p; // [p, q] 19 | int q; 20 | }; 21 | 22 | int maximumScore(int *nums, int numsSize, int *multipliers, int multipliersSize) { 23 | // 构建二叉树型表格 24 | struct Cell **table = malloc(sizeof(struct Cell *) * multipliersSize); 25 | for (int i = 0; i < multipliersSize; i++) { 26 | table[i] = malloc(sizeof(struct Cell) * (2 << i)); 27 | } 28 | 29 | for (int i = 0; i < multipliersSize; i++) { 30 | for (int j = 0; j < 1 << i; j++) { 31 | struct Cell cell = i == 0 ? (struct Cell){0, 0, numsSize - 1} : table[i - 1][j]; 32 | table[i][2 * j] = (struct Cell){cell.v + nums[cell.p] * multipliers[i], cell.p + 1, cell.q}; 33 | table[i][2 * j + 1] = (struct Cell){cell.v + nums[cell.q] * multipliers[i], cell.p, cell.q - 1}; 34 | } 35 | } 36 | 37 | int max = INT32_MIN; 38 | for (int i = 0; i < 1 << multipliersSize; i++) { 39 | if (table[multipliersSize - 1][i].v > max) { 40 | max = table[multipliersSize - 1][i].v; 41 | } 42 | } 43 | 44 | for (int i = 0; i < multipliersSize; i++) { 45 | free(table[i]); 46 | } 47 | free(table); 48 | 49 | return max; 50 | } 51 | 52 | void test(int expect, const char *nums, const char *multipliers) { 53 | arrayEntry *e1 = arrayParse1D(nums, ARRAY_INT); 54 | arrayEntry *e2 = arrayParse1D(multipliers, ARRAY_INT); 55 | 56 | EXPECT_EQ_INT(expect, maximumScore(arrayValue(e1), arraySize(e1), arrayValue(e2), arraySize(e2))); 57 | 58 | arrayFree(e2); 59 | arrayFree(e1); 60 | } 61 | 62 | int main(void) { 63 | test(14, "[1,2,3]", "[3,2,1]"); 64 | test(102, "[-5,-3,-3,-2,7,1]", "[-10,-5,3,4,6]"); 65 | 66 | return testOutput(); 67 | } 68 | -------------------------------------------------------------------------------- /c/data-structures/array-test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | */ 5 | 6 | #include "c/data-structures/array.h" 7 | #include "c/test.h" 8 | 9 | int type; 10 | int precision = 0; 11 | int dimensional; 12 | 13 | void testArrayRoundTrip(const char *str) { 14 | arrayEntry *e; 15 | switch (dimensional) { 16 | case 1: 17 | e = arrayParse1D(str, type); 18 | break; 19 | case 2: 20 | e = arrayParse2D(str, type); 21 | break; 22 | default: 23 | return; 24 | } 25 | if (type == ARRAY_DOUBLE) arraySetPrecision(e, precision); 26 | 27 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(str, arrayToString(e)); 28 | 29 | arrayFree(e); 30 | } 31 | 32 | int main(void) { 33 | /* 1 dimensional */ 34 | dimensional = 1; 35 | 36 | type = ARRAY_INT; 37 | testArrayRoundTrip("[]"); 38 | testArrayRoundTrip("[-3,-2,-1,0,1,2,3]"); 39 | testArrayRoundTrip("[2147483647,0,-2147483648]"); 40 | 41 | type = ARRAY_DOUBLE; 42 | testArrayRoundTrip("[]"); 43 | precision = 1; 44 | testArrayRoundTrip("[1.0,-1.2,0.3]"); 45 | precision = 5; 46 | testArrayRoundTrip("[1.00002,-1.29393,0.31233]"); 47 | 48 | type = ARRAY_CHAR; 49 | testArrayRoundTrip("[]"); 50 | testArrayRoundTrip("[a,b,c]"); 51 | testArrayRoundTrip("[!,@,#,%]"); 52 | 53 | type = ARRAY_STRING; 54 | testArrayRoundTrip("[]"); 55 | testArrayRoundTrip("[hello,world]"); 56 | testArrayRoundTrip("[h e l l o,w o rld]"); 57 | 58 | /* 2 dimensional */ 59 | dimensional = 2; 60 | 61 | type = ARRAY_INT; 62 | testArrayRoundTrip("[[]]"); 63 | testArrayRoundTrip("[[1,2],[3,4,5]]"); 64 | testArrayRoundTrip("[[],[],[],[],[-3],[],[0],[-2]]"); 65 | 66 | type = ARRAY_DOUBLE; 67 | testArrayRoundTrip("[[]]"); 68 | precision = 1; 69 | testArrayRoundTrip("[[0.0,1.0],[]]"); 70 | 71 | type = ARRAY_CHAR; 72 | testArrayRoundTrip("[[]]"); 73 | testArrayRoundTrip("[[a,b,c],[1,2,3,4],[),(,*,&,^,)]]"); 74 | 75 | type = ARRAY_STRING; 76 | testArrayRoundTrip("[[]]"); 77 | testArrayRoundTrip("[[hello],[world],[1234567890,!@#$%^&*()]]"); 78 | 79 | return testOutput(); 80 | } 81 | -------------------------------------------------------------------------------- /c/000-099/02-add-two-numbers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 题目就是两个正整数相加, 链表的顺序是数字的低位到高位. 6 | * 两个注意点: 7 | * 1: 链表长度不一致 8 | * 2: 进位 9 | */ 10 | 11 | #include /* malloc() */ 12 | #include "c/data-structures/linked-list.h" 13 | #include "c/test.h" 14 | 15 | /** 16 | * Definition for singly-linked list. 17 | * struct ListNode { 18 | * int val; 19 | * struct ListNode *next; 20 | * }; 21 | */ 22 | struct ListNode *addTwoNumbers(struct ListNode *l1, struct ListNode *l2) { 23 | struct ListNode *r = NULL, *lastNode = NULL; 24 | int carry = 0; 25 | while (l1 || l2) { 26 | if (!r) { // first node. 27 | lastNode = r = malloc(sizeof(struct ListNode)); 28 | } else { 29 | lastNode->next = malloc(sizeof(struct ListNode)); 30 | lastNode = lastNode->next; 31 | } 32 | 33 | int val1 = 0, val2 = 0; 34 | if (l1) { 35 | val1 = l1->val; 36 | l1 = l1->next; 37 | } 38 | 39 | if (l2) { 40 | val2 = l2->val; 41 | l2 = l2->next; 42 | } 43 | 44 | int val = val1 + val2 + carry; 45 | if (val > 9) { 46 | carry = 1; 47 | val -= 10; 48 | } else { 49 | carry = 0; 50 | } 51 | lastNode->val = val; 52 | lastNode->next = NULL; /* NOTE: 失败多次的原因竟然是没写这一行 */ 53 | } 54 | 55 | if (carry > 0) { /* 处理最后进位的情况 */ 56 | lastNode->next = malloc(sizeof(struct ListNode)); 57 | lastNode->next->val = carry; 58 | lastNode->next->next = NULL; 59 | } 60 | return r; 61 | } 62 | 63 | void test(const char *expect, const char *s1, const char *s2) { 64 | struct ListNode* l1 = linkedlistParse(s1); 65 | struct ListNode* l2 = linkedlistParse(s2); 66 | struct ListNode* actual = addTwoNumbers(l1, l2); 67 | 68 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, linkedlistToString(actual)); 69 | 70 | linkedlistFree(l1); 71 | linkedlistFree(l2); 72 | linkedlistFree(actual); 73 | } 74 | 75 | /* 76 | Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) 77 | Output: 7 -> 0 -> 8 78 | */ 79 | int main(void) { 80 | test("[7,0,8]", "[2,4,3]", "[5,6,4]"); 81 | 82 | return testOutput(); 83 | } 84 | -------------------------------------------------------------------------------- /c/000-099/03-longest-substring-without-repeating-characters.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * v1: O(n^2) 6 | * 暴力计算, 两层循环 7 | * v2: O(n) 8 | * 这里的 Table 可以理解成 HashTable, Key 是字符, Value 是该字符最新的 Index. 9 | * 当字符的 Index 更改的时候, 计算出差值, 最大的一个差值就是结果. 10 | */ 11 | 12 | #include /* malloc(), free() */ 13 | #include /* strlen(), memset() */ 14 | #include "c/test.h" 15 | 16 | int lengthOfLongestSubstring_v1(char *s) { 17 | int length = strlen(s); 18 | int i, j, len; 19 | 20 | int size = sizeof(char) * 128; 21 | char *table = malloc(size); 22 | int max = 1; 23 | 24 | for (i = 0; s[i] != '\0'; ++i) { 25 | if (i + max >= length) break; /* 如果最大长度已经大于剩余长度, break */ 26 | memset(table, 0, size); 27 | for (j = i, len = 0; s[j] != '\0'; ++j, ++len) { 28 | if (table[(int)s[j]] == 0) { 29 | table[(int)s[j]] = 1; 30 | } else { 31 | break; 32 | } 33 | } 34 | if (len > max) max = len; 35 | } 36 | 37 | free(table); 38 | return max; 39 | } 40 | 41 | #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 42 | int lengthOfLongestSubstring_v2(char* s) { 43 | int i = 0, j = 0, ans = 0, n = strlen(s); 44 | 45 | int size = sizeof(int) * 128; 46 | int *table = malloc(size); 47 | memset(table, 0, size); 48 | 49 | for (; j != n; j++) { 50 | i = MAX(i, table[(int)s[j]]); 51 | ans = MAX(ans, j + 1 - i); 52 | table[(int)s[j]] = j + 1; 53 | } 54 | 55 | free(table); 56 | return ans; 57 | } 58 | 59 | void test(int expect, char* s) { 60 | EXPECT_EQ_INT(expect, lengthOfLongestSubstring_v1(s)); 61 | EXPECT_EQ_INT(expect, lengthOfLongestSubstring_v2(s)); 62 | } 63 | 64 | /* 65 | Given "abcabcbb", the answer is "abc", which the length is 3. 66 | 67 | Given "bbbbb", the answer is "b", with the length of 1. 68 | 69 | Given "pwwkew", the answer is "wke", with the length of 3. 70 | Note that the answer must be a substring, "pwke" is a subsequence and not a substring. 71 | */ 72 | int main(void) { 73 | test(3, "abcabcbb"); 74 | test(1, "bbbbb"); 75 | test(3, "pwwkew"); 76 | 77 | return testOutput(); 78 | } 79 | -------------------------------------------------------------------------------- /c/300-399/336-palindrome-pairs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 暴力计算, 比较耗时 6 | */ 7 | 8 | #include 9 | #include /* malloc() */ 10 | #include /* strlen() */ 11 | #include "c/data-structures/array.h" 12 | #include "c/test.h" 13 | 14 | bool isPalindrome(const char *s1, const char *s2) { 15 | int l1 = strlen(s1), l2 = strlen(s2); 16 | for (int i = 0; i < (l1+l2)/2; ++i) 17 | if ((i < l1 ? s1[i] : s2[i-l1]) != (i < l2 ? s2[l2-i-1] : s1[l1-i+l2-1])) 18 | return false; 19 | 20 | return true; 21 | } 22 | 23 | /** 24 | * Return an array of arrays of size *returnSize. 25 | * The sizes of the arrays are returned as *columnSizes array. 26 | * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free(). 27 | */ 28 | int **palindromePairs(char **words, int wordsSize, int **columnSizes, int *returnSize) { 29 | int **rtn = malloc(sizeof(int*) * wordsSize * (wordsSize - 1)); /* 最多可能有 P(wordsSize, 2) 个 */ 30 | 31 | int i, j, size = 0; 32 | for (i = 0; i < wordsSize; i++) { 33 | for (j = 0; j < wordsSize; j++) { 34 | if (i == j) continue; 35 | if (isPalindrome(words[i], words[j])) { 36 | rtn[size] = malloc(sizeof(int) * 2); 37 | rtn[size][0] = i; 38 | rtn[size][1] = j; 39 | size++; 40 | } 41 | } 42 | } 43 | *returnSize = size; 44 | *columnSizes = malloc(sizeof(int) * size); 45 | for (i = 0; i < size; i++) (*columnSizes)[i] = 2; 46 | return rtn; 47 | } 48 | 49 | void test(const char *expect, const char *str) { 50 | arrayEntry *e = arrayParse1D(str, ARRAY_STRING); 51 | int *columnSizes; 52 | int returnSize; 53 | int **a = palindromePairs(arrayValue(e), arraySize(e), &columnSizes, &returnSize); 54 | 55 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString2D(a, returnSize, columnSizes, ARRAY_INT)); 56 | 57 | arrayFree(e); 58 | } 59 | 60 | int main(void) { 61 | test("[[0,1],[1,0]]", "[bat,tab,cat]"); 62 | test("[[0,1],[1,0],[2,4],[3,2]]", "[abcd,dcba,lls,s,sssll]"); 63 | test("[[0,3],[2,3],[3,0],[3,2]]", "[a,abc,aba,]"); 64 | 65 | return testOutput(); 66 | } 67 | -------------------------------------------------------------------------------- /c/000-099/15-3sum.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 先将数组排序, 在求解时会方便一些, 这样更容易跳过重复的数据 6 | */ 7 | 8 | #include /* qsort(), malloc() */ 9 | #include "c/data-structures/array.h" 10 | #include "c/test.h" 11 | #include "c/tools/compare.h" 12 | 13 | /** 14 | * Return an array of arrays of size *returnSize. 15 | * Note: The returned array must be malloced, assume caller calls free(). 16 | */ 17 | int **threeSum(int *nums, int numsSize, int* returnSize) { 18 | if (numsSize < 3) { 19 | *returnSize = 0; 20 | return NULL; 21 | } 22 | 23 | qsort(nums, numsSize, sizeof(int), compare_ints); 24 | 25 | /* 组合 Cn3 => n! / ((n-3)! * 3!) */ 26 | int **rt = malloc(sizeof(int *) * 27 | (numsSize * (numsSize-1) * (numsSize-2)) / 6); 28 | 29 | int top = 0, i; 30 | for (i = 0; i <= numsSize - 3; i++) { 31 | if (nums[i] > 0) break; 32 | if (i > 0 && nums[i] == nums[i-1]) continue; /* 跳过重复 */ 33 | int j = i + 1, 34 | k = numsSize - 1; 35 | while (j < k) { 36 | int sum = nums[i] + nums[j] + nums[k]; 37 | if (sum == 0) { 38 | rt[top] = malloc(sizeof(int) * 3); 39 | rt[top][0] = nums[i]; 40 | rt[top][1] = nums[j]; 41 | rt[top][2] = nums[k]; 42 | top++, j++, k--; 43 | while (j < k && nums[j] == nums[j-1]) j++; /* 跳过重复 */ 44 | while (j < k && nums[k] == nums[k+1]) k--; /* 跳过重复 */ 45 | } else if (sum > 0) { 46 | k--; 47 | } else { 48 | j++; 49 | } 50 | } 51 | } 52 | 53 | *returnSize = top; 54 | return rt; 55 | } 56 | 57 | void test(const char *expect, const char *str) { 58 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 59 | int returnSize; 60 | int **a = threeSum(arrayValue(e), arraySize(e), &returnSize); 61 | 62 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString2DSameCol(a, returnSize, 3, ARRAY_INT)); 63 | 64 | arrayFree(e); 65 | } 66 | 67 | /* 68 | For example, given array S = [-1, 0, 1, 2, -1, -4], 69 | 70 | A solution set is: 71 | [ 72 | [-1, 0, 1], 73 | [-1, -1, 2] 74 | ] 75 | */ 76 | int main() { 77 | test("[[-1,-1,2],[-1,0,1]]", "[-1, 0, 1, 2, -1, -4]"); 78 | 79 | return testOutput(); 80 | } 81 | -------------------------------------------------------------------------------- /c/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | readlink="readlink" 4 | if [[ $(uname) == "Darwin" ]]; then 5 | type greadlink >/dev/null 2>&1 || { 6 | echo >&2 "You need to install greadlink. (brew install coreutils)" 7 | echo >&2 "See https://stackoverflow.com/a/4031502" 8 | exit 1; 9 | } 10 | readlink="greadlink" 11 | fi 12 | 13 | # 进入脚本目录 14 | cd "$(dirname "$($readlink -f "$0")")/.." || exit 1 15 | 16 | usage() { 17 | printf "Complie and run solution.\n" 18 | printf "Usage:\n" 19 | printf " %s [OPTION]... ...\n" $0 20 | printf "\n" 21 | 22 | printf "OPTION:\n" 23 | printf " -m\tEnable memcheck. (use valgrind)\n" 24 | printf "\n" 25 | 26 | printf "COMMAND:\n" 27 | printf " all\tRun all solutions.\n" 28 | printf " test\tRun library's test.\n" 29 | printf " count\tCount the number of solved.\n" 30 | exit 1 31 | } 32 | 33 | run() { 34 | C_INCLUDE_PATH=$C_INCLUDE_PATH:$(pwd)/.. 35 | export C_INCLUDE_PATH 36 | lib=$(ls c/[a-z]*/*.c |grep -v test.c) 37 | 38 | for file in $1; do 39 | [ -f "$file" ] || { printf "NO.%d not found.\n" "$id"; exit 1; } 40 | 41 | printf '%s\n' "$file" 42 | excute=${file%.c} 43 | 44 | if ! gcc -std=c99 -Wall -o "$excute" "$file" $lib -lm; then exit 1; fi 45 | if ! $valgrind "$excute"; then fail_count=$((fail_count+1)); fi 46 | rm "$excute" 47 | rm -rf "$excute.DSYM" # https://github.com/LouisBrunner/valgrind-macos/ 会增加的文件 48 | done 49 | } 50 | 51 | main() { 52 | if [[ $# -lt 1 ]]; then usage; fi 53 | 54 | for arg in "$@"; do 55 | if [[ $arg == "-m" ]]; then 56 | type valgrind >/dev/null 2>&1 || { echo >&2 "You need to install valgrind."; exit 1; } 57 | valgrind="valgrind"; 58 | fi 59 | done 60 | 61 | for arg in "$@"; do 62 | case $arg in 63 | "all") 64 | run "c/[0-9]*/*.c" 65 | ;; 66 | "lib") 67 | run "c/[a-z]*/*-test.c" 68 | ;; 69 | "count") 70 | printf "\e[38;5;2mSolved: %s\e[0m\n" "$(find c/[0-9]*/*.c |wc -l)" 71 | ;; 72 | [0-9]*) 73 | id=$(printf "%02d" "$arg") 74 | run "c/[0-9]*/$id-*.c" 75 | ;; 76 | [-]*) 77 | ;; 78 | *) 79 | run "c/000/$arg*.c" 80 | ;; 81 | esac 82 | done 83 | 84 | exit $fail_count 85 | } 86 | 87 | main "$@" 88 | -------------------------------------------------------------------------------- /c/100-199/105-construct-binary-tree-from-preorder-and-inorder-traversal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 树的根节点是 preorder[0], 6 | * 在 inorder 中找到等于 preorder[0] 值的位置, 7 | * 然后左侧即左树, 右侧即右树, 8 | * 如此反复. 9 | */ 10 | 11 | #include /* assert() */ 12 | #include /* malloc() */ 13 | #include "c/data-structures/array.h" 14 | #include "c/data-structures/binary-tree.h" 15 | #include "c/test.h" 16 | 17 | /** 18 | * Definition for a binary tree node. 19 | * struct TreeNode { 20 | * int val; 21 | * struct TreeNode *left; 22 | * struct TreeNode *right; 23 | * }; 24 | */ 25 | struct TreeNode *buildTree(int *preorder, int preorderSize, int *inorder, int inorderSize) { 26 | assert(preorderSize == inorderSize); 27 | int size = preorderSize; 28 | 29 | if (!size)return NULL; 30 | 31 | struct TreeNode *root = malloc(sizeof(struct TreeNode)); 32 | root->val = preorder[0]; 33 | if (size == 1) { 34 | root->left = NULL; 35 | root->right = NULL; 36 | } else { 37 | int index = -1; 38 | for (int i = 0; i < size; ++i) { 39 | if (inorder[i] == root->val) { 40 | index = i; 41 | break; 42 | } 43 | } 44 | root->left = buildTree(preorder + 1, index, 45 | inorder, index); 46 | root->right = buildTree(preorder + 1 + index, size - 1 - index, 47 | inorder + 1 + index, size - 1 - index); 48 | } 49 | return root; 50 | } 51 | 52 | void test(const char *expect, const char *preorderStr, const char *inorderStr) { 53 | arrayEntry *preorder = arrayParse1D(preorderStr, ARRAY_INT); 54 | arrayEntry *inorder = arrayParse1D(inorderStr, ARRAY_INT); 55 | struct TreeNode *tree = buildTree(arrayValue(preorder), arraySize(preorder), 56 | arrayValue(inorder), arraySize(inorder)); 57 | 58 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, treeToString(tree)); 59 | 60 | treeFree(tree); 61 | arrayFree(preorder); 62 | arrayFree(inorder); 63 | } 64 | 65 | int main(void) { 66 | test("[3,9,20,null,null,15,7]", 67 | "[3,9,20,15,7]", 68 | "[9,3,15,20,7]"); 69 | 70 | test("[4,1,null,null,2,null,3]", 71 | "[4,1,2,3]", 72 | "[1,2,3,4]"); 73 | 74 | return testOutput(); 75 | } 76 | -------------------------------------------------------------------------------- /c/000-099/19-remove-nth-node-from-end-of-list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2018, Saul Lawliet 3 | * All rights reserved. 4 | 5 | * v1: 先计算链表的长度, 把问题变成删除从头开始的第n个节点 6 | * v2: 维持两个链表(slow, fast) 7 | * 1. 先将 fast 后移n次 8 | * 2. 如果 fast 不是空, 同时后移 slowfast, 9 | * 直到 fast 为空时, slow 就是要删除的节点 10 | */ 11 | 12 | #include /* free() */ 13 | #include "c/data-structures/linked-list.h" 14 | #include "c/test.h" 15 | 16 | /** 17 | * Definition for singly-linked list. 18 | * struct ListNode { 19 | * int val; 20 | * struct ListNode *next; 21 | * }; 22 | */ 23 | struct ListNode *removeNthFromEnd_v1(struct ListNode *head, int n) { 24 | struct ListNode *p = head; 25 | int index = linkedlistLength(head) - n - 1; /* 要获取删除节点的上一个 */ 26 | if (index == -1) { /* 此时删除头节点 */ 27 | head = head->next; 28 | free(p); 29 | } else { 30 | while (index--) { 31 | p = p->next; 32 | } 33 | struct ListNode *removeNode = p->next; 34 | p->next = removeNode->next; 35 | free(removeNode); 36 | } 37 | return head; 38 | } 39 | 40 | struct ListNode *removeNthFromEnd_v2(struct ListNode *head, int n) { 41 | struct ListNode *slow = head, *fast = head; 42 | while (n--) { 43 | fast = fast->next; 44 | } 45 | 46 | if (fast == NULL) { 47 | head = head->next; 48 | free(slow); 49 | return head; 50 | } 51 | 52 | while (fast->next != NULL) { 53 | slow = slow->next; 54 | fast = fast->next; 55 | } 56 | struct ListNode *removeNode = slow->next; 57 | slow->next = removeNode->next; 58 | free(removeNode); 59 | return head; 60 | } 61 | 62 | void test(const char *expect, const char *s, int n) { 63 | struct ListNode *list; 64 | 65 | list = removeNthFromEnd_v1(linkedlistParse(s), n); 66 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, linkedlistToString(list)); 67 | linkedlistFree(list); 68 | 69 | list = removeNthFromEnd_v2(linkedlistParse(s), n); 70 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, linkedlistToString(list)); 71 | linkedlistFree(list); 72 | } 73 | 74 | int main(void) { 75 | test("[1,2,3,4]", "[1,2,3,4,5]", 1); 76 | test("[1,2,3,5]", "[1,2,3,4,5]", 2); 77 | test("[1,2,4,5]", "[1,2,3,4,5]", 3); 78 | test("[1,3,4,5]", "[1,2,3,4,5]", 4); 79 | test("[2,3,4,5]", "[1,2,3,4,5]", 5); 80 | 81 | return testOutput(); 82 | } 83 | -------------------------------------------------------------------------------- /Database.sql: -------------------------------------------------------------------------------- 1 | -- https://leetcode.com/problemset/database/ 2 | -- 175. Combine Two Tables 3 | SELECT p.FirstName, p.LastName, a.City, a.State 4 | FROM Person p 5 | LEFT OUTER JOIN Address a ON a.PersonId = p.PersonId; 6 | 7 | 8 | -- 176. Second Highest Salary 9 | SELECT max(Salary) SecondHighestSalary FROM Employee 10 | WHERE Salary < (SELECT max(Salary) FROM Employee); 11 | 12 | 13 | -- 177. Nth Highest Salary 14 | 15 | 16 | -- 178. Rank Scores 17 | SELECT 18 | Score, 19 | @rank := @rank + (@last <> @last := Score) Rank 20 | FROM Scores, (SELECT @rank := 0, @last := -1) init 21 | ORDER BY Score DESC; 22 | 23 | 24 | -- 180. Consecutive Numbers 25 | SELECT DISTINCT num ConsecutiveNums FROM 26 | (SELECT 27 | num, 28 | @count := if(@last = @last := num, @count + 1, 1) n 29 | FROM Logs) t, 30 | (SELECT @count := 0, @last:=(SELECT num FROM Logs Limit 1)) init 31 | WHERE t.n >= 3; 32 | 33 | 34 | -- 181. Employees Earning More Than Their Managers 35 | SELECT e1.Name Employee 36 | FROM Employee e1 37 | INNER JOIN Employee e2 ON e1.ManagerId = e2.Id 38 | WHERE e1.Salary > e2.Salary; 39 | 40 | 41 | -- 182. Duplicate Emails 42 | SELECT Email 43 | FROM Person 44 | GROUP BY Email 45 | HAVING COUNT(Email) > 1; 46 | 47 | 48 | -- 183. Customers Who Never Order 49 | -- I. 50 | SELECT c.Name Customers 51 | FROM Customers c 52 | LEFT OUTER JOIN Orders o ON c.Id = o.CustomerId 53 | WHERE o.Id IS NULL; 54 | -- II. 55 | SELECT Name Customers 56 | FROM Customers 57 | WHERE Id NOT IN ( 58 | SELECT CustomerId 59 | FROM Orders 60 | ); 61 | 62 | 63 | -- 184. Department Highest Salary 64 | SELECT d.name Department, e.name Employee, e.Salary 65 | FROM (SELECT DepartmentId, max(Salary) Salary FROM Employee GROUP BY DepartmentId) tmp 66 | INNER JOIN Department d 67 | ON tmp.DepartmentId = d.Id 68 | INNER JOIN Employee e 69 | ON tmp.DepartmentId = e.DepartmentId AND tmp.Salary = e.Salary; 70 | 71 | -- 185. Department Top Three Salaries 72 | 73 | 74 | -- 196. Delete Duplicate Emails 75 | DELETE FROM Person 76 | WHERE Id NOT IN ( 77 | SELECT Id from ( 78 | SELECT MIN(Id) Id 79 | FROM Person 80 | GROUP BY Email 81 | ) tmp 82 | ); 83 | 84 | 85 | -- 197. Rising Temperature 86 | SELECT w2.Id 87 | FROM Weather w1 88 | INNER JOIN Weather w2 ON w2.Date = SUBDATE(w1.Date, -1) 89 | WHERE w1.Temperature < w2.Temperature; 90 | 91 | 92 | -- 262. Trips and Users 93 | -------------------------------------------------------------------------------- /c/000-099/39-combination-sum.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 递归解即可 6 | */ 7 | 8 | #include /* malloc(), free(), qsort() */ 9 | #include /* memcpy() */ 10 | #include "c/data-structures/array.h" 11 | #include "c/test.h" 12 | #include "c/tools/compare.h" 13 | 14 | #define MAX_ROW_SIZE 1000 15 | #define MAX_COL_SIZE 100 16 | 17 | void dfs(int ***rtn, int **columnSizes, int *returnSize, 18 | int *candidateds, int candidatesSize, int target, int *nums, int numsSize, int order) { 19 | if (target == 0) { 20 | (*columnSizes)[*returnSize] = numsSize; 21 | memcpy(((*rtn)[*returnSize] = malloc(sizeof(int *) * numsSize)), nums, sizeof(int) * numsSize); 22 | (*returnSize)++; 23 | return; 24 | } 25 | for (int i = order; i < candidatesSize; ++i) { 26 | if (candidateds[i] > target) return; 27 | nums[numsSize] = candidateds[i]; 28 | dfs(rtn, columnSizes, returnSize, 29 | candidateds, candidatesSize, target - candidateds[i], nums, numsSize + 1, i); 30 | } 31 | } 32 | 33 | /** 34 | * Return an array of arrays of size *returnSize. 35 | * The sizes of the arrays are returned as *columnSizes array. 36 | * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free(). 37 | */ 38 | int **combinationSum(int *candidates, int candidatesSize, int target, int **columnSizes, int *returnSize) { 39 | qsort(candidates, candidatesSize, sizeof(int), compare_ints); 40 | *returnSize = 0; 41 | int **rtn = malloc(sizeof(int *) * MAX_ROW_SIZE); 42 | *columnSizes = malloc(sizeof(int) * MAX_ROW_SIZE); 43 | int *nums = malloc(sizeof(int) * MAX_COL_SIZE); 44 | dfs(&rtn, columnSizes, returnSize, 45 | candidates, candidatesSize, target, nums, 0, 0); 46 | free(nums); 47 | return rtn; 48 | } 49 | 50 | void test(const char *expect, const char *str, int target) { 51 | arrayEntry *e = arrayParse1D(str, ARRAY_INT); 52 | int *columnSizes; 53 | int returnSize; 54 | int **a = combinationSum(arrayValue(e), arraySize(e), target, &columnSizes, &returnSize); 55 | 56 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString2D(a, returnSize, columnSizes, ARRAY_INT)); 57 | 58 | arrayFree(e); 59 | } 60 | 61 | int main(void) { 62 | test("[[2,2,3],[7]]", "[2, 3, 6, 7]", 7); 63 | 64 | return testOutput(); 65 | } 66 | -------------------------------------------------------------------------------- /c/100-199/113-path-sum-ii.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Saul Lawliet 3 | * All rights reserved. 4 | * 5 | * 跟 No.112, 一样的思路, 只是需要记录一下路径 6 | */ 7 | 8 | #include "c/data-structures/array.h" 9 | #include "c/data-structures/binary-tree.h" 10 | #include "c/test.h" 11 | 12 | void backtracking(int **tmp, int tmpIndex, int ***returnArray, int *returnSize, int **returnColumnSizes, struct TreeNode *root, int targetSum) { 13 | if (root == NULL) return; 14 | 15 | (*tmp)[tmpIndex++] = root->val; 16 | 17 | if (!root->left && !root->right) { 18 | if (targetSum == root->val) { 19 | int *arr = malloc(sizeof(int) * tmpIndex); 20 | for (int i = 0; i < tmpIndex; i++) 21 | arr[i] = (*tmp)[i]; 22 | (*returnColumnSizes)[*returnSize] = tmpIndex; 23 | (*returnArray)[*returnSize] = arr; 24 | (*returnSize)++; 25 | } 26 | } 27 | 28 | backtracking(tmp, tmpIndex, returnArray, returnSize, returnColumnSizes, root->left, targetSum - root->val); 29 | backtracking(tmp, tmpIndex, returnArray, returnSize, returnColumnSizes, root->right, targetSum - root->val); 30 | } 31 | 32 | /** 33 | * Return an array of arrays of size *returnSize. 34 | * The sizes of the arrays are returned as *returnColumnSizes array. 35 | * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free(). 36 | */ 37 | int **pathSum(struct TreeNode *root, int targetSum, int *returnSize, int **returnColumnSizes) { 38 | *returnSize = 0; 39 | int **returnArray = malloc(sizeof(int *) * 1000); // 假设 1k 个 40 | *returnColumnSizes = malloc(sizeof(int) * 1000); 41 | 42 | // 拿到高度, 绝定动态数组长度 43 | int height = treeHeight(root); 44 | int *tmp = malloc(sizeof(int) * height); 45 | 46 | backtracking(&tmp, 0, &returnArray, returnSize, returnColumnSizes, root, targetSum); 47 | 48 | free(tmp); 49 | 50 | return returnArray; 51 | } 52 | 53 | void test(const char *expect, const char *rootStr, int targetSum) { 54 | struct TreeNode* root = treeParse(rootStr); 55 | 56 | int returnSize; 57 | int *returnColumnSizes; 58 | 59 | int **returnArray = pathSum(root, targetSum, &returnSize, &returnColumnSizes); 60 | 61 | EXPECT_EQ_STRING_AND_FREE_ACTUAL(expect, arrayToString2D(returnArray, returnSize, returnColumnSizes, ARRAY_INT)); 62 | 63 | treeFree(root); 64 | } 65 | 66 | int main(void) { 67 | test("[[5,4,11,2],[5,8,4,5]]", "[5,4,8,11,null,13,4,7,2,null,null,5,1]", 22); 68 | 69 | return testOutput(); 70 | } 71 | --------------------------------------------------------------------------------