22. Generate Parentheses
1 class Solution 2 { 3 private: 4 void generateParenthesis(vector<string> &v, string s, int l, int r) // l和r记录剩余左右括号的数量 5 { 6 if(l == 0 && r == 0) // 当且仅当左右括号数量都为0时,正常结束 7 v.push_back(s); 8 9 if(l > 0) 10 generateParenthesis(v, s + "(", l - 1, r); 11 if(r > 0 && l < r) // 剩余的右括号数量比左括号多时才能添加右括号 12 generateParenthesis(v, s + ")", l, r - 1); 13 } 14 public: 15 vector<string> generateParenthesis(int n) 16 { 17 vector<string> v; 18 generateParenthesis(v, "", n, n); 19 return v; 20 } 21 };
括号匹配数是一个卡特兰数,f(x) = (2n)!/((n+1)! * n!) , f(3) = 5
当作dfs处理,这样得到的顺序是"("从多到少的顺序。
用python写
1 class Solution(object): 2 def generateParenthesis(self, n): 3 """ 4 :type n: int 5 :rtype: List[str] 6 """ 7 return ['(' + litem + ')' + ritem for i in range(n) for litem in self.generateParenthesis(i) for ritem in self.generateParenthesis(n-1-i)] or ['']
python写法的示意图:
l、r 的值相当于left、right位置上有几个括号
按这个dfs的结果是()()(), ()(()), (())(), (()()), ((()))
15. 3Sum
可以用hash存一下,然后两个for循环,内部加hashSearch(-(num[i] + num[j]) ), hash部分的代码参考2sum
1 /** 2 * Return an array of arrays of size *returnSize. 3 * Note: The returned array must be malloced, assume caller calls free(). 4 */ 5 6 typedef struct linkList{ 7 int data; 8 int index_nums; 9 struct linkList *ptr; 10 }linkList; 11 _Bool hashSearch(int num1, int num2, int* index_num3, int val, int hashTSize, linkList *hashT); 12 int** threeSum(int* nums, int numsSize, int* returnSize) { 13 int hashTSize = numsSize; 14 int index_num3, target; 15 int index_set = 0; 16 int **ptr_set = calloc(1024, sizeof(int *)); 17 linkList *hashT = calloc(hashTSize, sizeof(linkList)); 18 19 char mark[1024] = {0}; 20 for(int i = 0; i < numsSize; i++) hashInsert(i, nums[i], hashTSize, hashT); 21 22 for(int i = 0; i < numsSize-1; i++) 23 for(int j = i+1; j < numsSize; j++){ 24 target = -(nums[i] + nums[j]); 25 if(hashSearch(i, j, &index_num3, target, hashTSize, hashT)) { 26 // if (mark[i] && mark[j] && mark[index_num3]) continue; 27 if (index_num3 < j) continue; 28 ptr_set[index_set] = malloc(3 * sizeof(int)); 29 ptr_set[index_set][0] = nums[i]; 30 ptr_set[index_set][1] = nums[j]; 31 ptr_set[index_set][2] = nums[index_num3]; 32 // mark[i] = mark[j] = mark[index_num3] = 1; 33 ++index_set; 34 } 35 } 36 *returnSize = index_set; 37 return ptr_set; 38 } 39 void hashInsert(int i, int val, int hashSize, linkList *hashT) { 40 int temp_val; 41 temp_val = (val < 0) ? -val : val; 42 linkList *temp_ptr = &hashT[temp_val % hashSize]; 43 while(temp_ptr->ptr) temp_ptr = temp_ptr->ptr; 44 temp_ptr->ptr = calloc(1, sizeof(linkList)); 45 temp_ptr->ptr->data = val; 46 temp_ptr->ptr->index_nums = i; 47 } 48 _Bool hashSearch(int exist_index1, int exist_index2, int* return_index, int val, int hashTSize, linkList *hashT){ 49 int temp_val; 50 temp_val = (val < 0) ? -val : val; 51 linkList *temp_str = &hashT[temp_val % hashTSize]; 52 for (temp_str = temp_str->ptr; temp_str; temp_str = temp_str->ptr) 53 if (temp_str->data == val && temp_str->index_nums != exist_index1 && temp_str->index_nums != exist_index2){ 54 *return_index = temp_str->index_nums; 55 return true; 56 } 57 return false; 58 }
但是处理不了
正统方法还是用sort,排序以后两端比较。
2. Add Two Numbers
使用二级指针:
1 struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) 2 { 3 if (l1 == NULL) 4 return l2; 5 if (l2 == NULL) 6 return l1; 7 struct ListNode *head_l3 = NULL; 8 struct ListNode **ppl3 = &head_l3; 9 int v = 0; 10 while (l1 != NULL || l2 != NULL || v) { 11 if (l1 != NULL) { 12 v += l1->val; 13 l1 = l1->next; 14 } 15 if (l2 != NULL) { 16 v += l2->val; 17 l2 = l2->next; 18 } 19 struct ListNode *pl3 = (struct ListNode *) malloc(sizeof(struct ListNode)); 20 pl3->next = NULL; 21 pl3->val = v % 10; 22 v /= 10; 23 24 *ppl3 = pl3; 25 ppl3 = &pl3->next; 26 27 } 28 return head_l3; 29 }
使用二级指针就不用使用dummy head节点,因为prePtr->next和head都是指针,用二级指针就可以不加区分地表示两者
(不加区分地表示两者的意思是:令pp = &prePtr->next 或 pp = &head, 那么*pp这个表示形式就可以表达两种语义,表达能力更强)
为了创建并链接新结点,在while循环内存在形如prePtr->next = newPtr; prePtr = newPtr;的表达,同时第一次进入while时应该实现 head = newPtr; prePtr = newPtr;
如果不使用二级指针,那么就要将第一次进入while时的行为写成 dummy->next = newPtr; prePtr = newPtr;
不使用二级指针的方式如下:
1 struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) 2 { 3 struct ListNode* res,*pt,*node; 4 int j = 0,temp = 0; 5 res = (struct ListNode*) malloc(sizeof(struct ListNode)); 6 res->next = NULL; 7 pt = res; 8 while (l1 != NULL || l2 != NULL || j!=0) 9 { 10 node = (struct ListNode*) malloc(sizeof(struct ListNode)); 11 temp = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + j; 12 node->val = temp%10; 13 j = temp/10; 14 node->next = NULL; 15 pt->next = node; 16 pt = node; 17 l1 = l1 ? l1->next : l1; 18 l2 = l2 ? l2->next : l2; 19 } 20 pt = res->next; 21 free(res); 22 return pt; 23 }
更多二级指针用法参考:http://coolshell.cn/articles/8990.html#comment-326334 、http://coolshell.cn/articles/9859.html
3. Longest Substring Without Repeating Characters
因为出现的元素都是ascii字符,可以用一个128个元素的数组记录(ascii使用8位,但是头一位是0,所以范围是000 0000 ~ 0111 1111)
1 int lengthOfLongestSubstring(char* s) { 2 int h[128]; 3 int index1 = 0, index2 = 0; 4 int max = 0, i = 0; 5 for(i = 0; i < 128; i++){ 6 h[i] = -1; 7 } 8 9 while(*s != '\0'){ 10 //char *s last appear at index h[*s] 11 if(h[*s] >= index1){ //repeat 12 index1 = h[*s] + 1; 13 } 14 if(index2 - index1 + 1 > max){ 15 max = index2 - index1 + 1; 16 } 17 h[*s] = index2; //update char *s last position 18 index2++; 19 s++; 20 } 21 return max; 22 }
5. Longest Palindromic Substring
char *longestPalindrome(char *s) { int start = 0, end = 0; for (int i = 0; i < strlen(s); i++) { int len1 = expand(s, i, i); int len2 = expand(s, i, i+1); int len = len1 > len2? len1 : len2; if (len > end - start) { start = i - (len - 1)/2; end = i + len/2; } } int ans_len = end - start + 2; char *ans = malloc(sizeof(char) * ans_len); strncpy(ans, s + start, end-start + 1); ans[end-start+1] = '\0'; return ans; } int expand(char *s, int left, int right) { int L = left, R = right; while (L >= 0 && R < strlen(s) && s[L] == s[R]) { L--; R++; } return R - L - 1; }
11. Container With Most Water
水位由两个挡板间较低的挡板决定,所以可以从两端设置index i, j,每次移动较低的挡板并计算新的面积是否是最大面积。
1 int maxArea(int* heights, int size) 2 { 3 int l=0, r=size-1; 4 int max = 0; 5 while(l < r) 6 { 7 int area = (r-l)*(heights[l] < heights[r]? heights[l++] : heights[r--]); 8 max = max > area? max : area; 9 } 10 return max; 11 }
12. Integer to Roman
1 char* intToRoman(int num) { 2 char *M[] = {"", "M", "MM", "MMM"}; 3 char *C[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}; 4 char *X[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}; 5 char *I[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}; 6 char *ans = malloc(sizeof(char)*20); 7 strcat(strcat(strcat(strcat(ans,M[num/1000]),C[(num%1000)/100]), X[(num%100)/10]), I[num%10]); 8 // snprintf(ans, 20, "%s%s%s%s", M[num/1000], C[(num%1000)/100], X[(num%100)/10], I[num%10]); 9 return ans; 10 }
13. Roman to Integer
阿拉伯数字从左至右是降序的,而罗马数字除了降序也会出现升序,比如表示4的时候使用IV表示5-1.
1 int romanToInt(char *s) { 2 #define _M 1000 3 #define _D 500 4 #define _C 100 5 #define _L 50 6 #define _X 10 7 #define _V 5 8 #define _I 1 9 10 int result = 0; 11 int i; 12 int last = _M; 13 for(i = 0;i < strlen(s);i++) 14 { 15 switch (s[i]) 16 { 17 case 'M': 18 result = (last >= _M ? result + _M:result + _M - (last << 1)); 19 last = _M; 20 break; 21 case 'D': 22 result = (last >= _D ? result + _D:result + _D - (last << 1)); 23 last = _D; 24 break; 25 case 'C': 26 result = (last >= _C ? result + _C:result + _C - (last << 1)); 27 last = _C; 28 break; 29 case 'L': 30 result = (last >= _L ? result + _L:result + _L - (last << 1)); 31 last = _L; 32 break; 33 case 'X': 34 result = (last >= _X ? result + _X:result + _X - (last << 1)); 35 last = _X; 36 break; 37 case 'V': 38 result = (last >= _V ? result + _V:result + _V - (last << 1)); 39 last = _V; 40 break; 41 case 'I': 42 result = (last >= _I ? result + _I:result + _I - (last << 1)); 43 last = _I; 44 break; 45 } 46 47 } 48 return result; 49 }
16. 3Sum Closest
这题与3sum很相似,不同之处在于不用查重,如果有等于target的就直接返回target,否则就返回最近接近的target的3sum。
1 int cmp(int *p1, int *p2); 2 int threeSumClosest(int* nums, int numsSize, int target) { 3 qsort(nums, numsSize, sizeof(int), cmp); 4 int i, l , r, sum, minoff, ans; 5 minoff = INT32_MAX; 6 ans = 0; 7 for(i = 0; i < numsSize; i++){ 8 l = i + 1; 9 r = numsSize - 1; 10 while(l < r){ 11 sum = nums[i] + nums[l] + nums[r]; 12 if(sum == target){ 13 return target; 14 } 15 if(abs(sum-target) < minoff){ 16 minoff = abs(sum-target); 17 ans = sum; 18 } 19 else if(sum-target > 0){ 20 r--; 21 } 22 else { 23 l++; 24 } 25 } 26 } 27 return ans; 28 } 29 int cmp(int *p1, int *p2) 30 { 31 return *p1-*p2; 32 }
17. Letter Combinations of a Phone Number
c的字符串处理很鸡肋,,,有很多手动管理内存的操作
class Solution { public: vector<string> letterCombinations(string digits) { vector<string> result; DFS(digits,0,"",result); return result; } private: void DFS(string digits,int cur,string path,vector<string> &result){ string keyboard[] = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"}; if(cur == digits.length()){ result.push_back(path); return; }//if int len = keyboard[digits[cur] - '0'].length(); for(int i = 0;i < len;++i){ char c = keyboard[digits[cur] - '0'][i]; DFS(digits,cur + 1,path + c,result); }//for } };
因为只能传指针(或者把字符数组包在一个结构体内传结构体),所以像DFS(digits,cur + 1,path + c,result); 这样的代码要先malloc一个指针然后用strcat把字符串连接到这个指针,还要在使用之后自己free,还是直接使用string类比较方便。
29. Divide Two Integers
模拟长除法
1 int divide(int x, int y) { 2 // Note: The Solution object is instantiated only once. 3 // int x = dividend, y = divisor; 4 if (y == 0) return INT32_MAX; 5 if (y == -1 && x == INT32_MIN) return INT32_MAX; 6 if (y == 1 && x == INT32_MIN) return INT32_MIN; 7 unsigned int px = (x < 0)? -x : x; 8 unsigned int py = (y < 0)? -y : y; 9 int ans = 0; 10 // printf("at first px:%u\npy:%u", px,py); 11 while(px >= py) { 12 int shift = 0; 13 while (px >= (py << shift)){ 14 ++shift; 15 if(px == (py<<shift)){ 16 shift++; 17 break; 18 } 19 // printf("py<20 } 21 shift--; 22 23 ans += 1 << (shift); 24 25 px -= (py << shift); 26 } 27 return (int)((x ^ y) >> 31) ? (-ans) : (ans); 28 }
以上的写法相当于每次从0开始检索一个最长位,最坏的情况下每次都要检索到头,比如对于11111111..检索次数是 31 + 30 + 29 + 28 + 27 + 26 + 25 + 24...
也可以先找出一个最高位,然后从这个最高位向0检索,最坏的情况下也只用检索31次。
因为我是转成unsigned,所以要小心2147483648 << 1 得到0的情况(一开始没察觉到检查了半天,最后加了个if x == y return 1;)
1 int divide(int x, int y) { 2 if (y == 0) return INT32_MAX; 3 if (y == -1 && x == INT32_MIN) return INT32_MAX; 4 if (y == 1 && x == INT32_MIN) return INT32_MIN; 5 if (x == y) return 1; 6 unsigned int px = (x < 0)? -x : x; 7 unsigned int py = (y < 0)? -y : y; 8 int ans = 0; 9 int shift = 0; 10 while(px >= (py<<shift)) { 11 shift++; 12 if(px == (py<<shift)){ 13 shift++; 14 break; 15 } 16 } 17 shift--; 18 while (shift >= 0) { 19 if (px >= (py << shift)) { 20 ans += (1 << shift); 21 px -= (py << shift); 22 } 23 shift--; 24 } 25 return ((x ^ y) >> 31) ? (-ans) : (ans); 26 }