leetcode热题100(2)
leetcode-73-矩阵置零
法一:两个标记数组分别记录每一行和每一列是否有零出现
时间复杂度O(mn) 空间复杂度O(m+n)
void setZeroes(int** matrix, int matrixSize, int* matrixColSize) { int m = matrixSize; int n = matrixColSize[0]; int row[m], col[n]; memset(row, 0, sizeof(row)); memset(col, 0, sizeof(col)); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (!matrix[i][j]) { row[i] = col[j] = true; } } } for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (row[i] || col[j]) { matrix[i][j] = 0; } } }}
法二:使用两个标记量
可以用矩阵的第一行和第一列代替方法一中的两个标记数组,以达到O(!)的额外空间。但这样会导致原数组的第一行和第一列被修改,无法记录它们是否原本包含0,因此需要额外使用两个标记量分别记录第一行和第一列是否原本包含0
时间复杂度O(mn) 空间复杂度O(1)
void setZeroes(int** matrix, int matrixSize, int* matrixColSize) { int m = matrixSize; int n = matrixColSize[0]; int flag_col0 = false, flag_row0 = false; for(int i = 0 ; i < m ; i++){ if(!matrix[i][0]) flag_col0 = true; } for(int j = 0 ; j < n ; j++){ if(!matrix[0][j]) flag_row0 = true; } for(int i = 1 ; i < m ; i++){ for(int j = 1 ; j < n ; j++){ if(!matrix[i][j]) matrix[i][0] = matrix[0][j] = 0; } } for(int i = 1 ; i < m ; i++){ for(int j = 1 ; j < n ; j++){ if(!matrix[i][0] || !matrix[0][j]) matrix[i][j] = 0; } } if(flag_col0){ for(int i = 0 ; i < m ;i++){ matrix[i][0] = 0; } } if(flag_row0){ for(int j = 0 ; j < n ; j++){ matrix[0][j] = 0; } }}
leetcode-48-旋转图像
转置+按列翻转
void rotate(int** matrix, int matrixSize, int* matrixColSize) { int temp; int n = matrixSize; for(int i = 0 ; i < n ; i++){ for(int j = i ; j < n ; j++){ if(i == j) continue; temp = matrix[i][j]; matrix[i][j] = matrix[j][i]; matrix[j][i] = temp; } } for(int j = 0 ; j < n/2 ; j++){ for(int i = 0 ; i< n ; i++){ temp = matrix[i][j]; matrix[i][j] = matrix[i][n-j-1]; matrix[i][n-j-1] = temp; } }}
leetcode-240-搜索二维矩阵II
1.二分查找
由于矩阵每行都是升序的,所以可以依次遍历每行进行二分查找
时间O(mlogn) 空间O(1)
int binarySearch(int* nums, int size, int target){ int l = 0, r = size-1; while(l target){ r = mid-1; } else if(nums[mid] < target){ l = mid+1; } else{ return mid; } } return -1;}bool searchMatrix(int** matrix, int matrixSize, int* matrixColSize, int target){ int index; for(int i = 0; i = 0) return true; } return false;}
2.Z字形查找
从矩阵右上角matrix[i][j]开始寻找
若matrix[i][j] > target 列--
若matrix[i][j] < target 行++
时间O(m+n) 空间O(1)
bool searchMatrix(int** matrix, int matrixSize, int* matrixColSize, int target) { int m = matrixSize, n = matrixColSize[0]; int i = 0, j = n - 1; while (i = 0) { if (matrix[i][j] == target) { return true; } if (matrix[i][j] < target) { i++; } else { j--; } } return false;}
leetcode-160-相交链表
1.两个链表相交
设headA和headB的长度分别是m和n。假设headA不相交部分有a个节点,headB不相交部分有b个节点,两个链表相交部分有c个节点,则 a+c = m, b+c = n
(1)若a = b,则两个指针会同时到达两个链表相交部分,此时返回相交节点
(2)若a 不等于 b,则指针pA遍历完headA,然后指向headB,指针pB遍历完headB,然后指向headA,然后两个指针继续移动,在指针pA移动了a+c+b次,指针pB移动了b+c+a次之后,两个指针会同时达到相交节点
2.两个链表不相交
设headA和headB的长度分别是m和n。考虑当m等于n 和 m不等于n
(1)若m 等于 n,则两个指针会同时到达链尾,返回NULL
(2)若m 不等于 n,由于链表没有公共节点,两个指针不会同时到达链尾,因此两个指针都会遍历完两个链表,在指针pA移动了m+n次,指针pB移动了n+m次后,两个指针都会同时变为NULL
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) { if(headA == NULL || headB == NULL) return NULL; struct ListNode *pA = headA, *pB = headB; while(pA != pB){ pA = pA == NULL ? headB : pA->next; pB = pB == NULL ? headA : pB->next; } return pA;}
2.getLen求不带头结点的链表长度
int getLen(struct ListNode* head){ int len = 1; struct ListNode* p = head; while(p != NULL){ p = p->next; len++; } return len;}struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) { int lenA = getLen(headA); int lenB = getLen(headB); struct ListNode *pA, *pB; for(pA = headA ; lenA > lenB ; lenA--){ pA = pA->next; } for(pB = headB ; lenA next; } while(pA != NULL && pA != pB){ pA = pA->next; pB = pB->next; } return pA;}
leetcode-234-回文链表
双指针:
找到链表的中间结点,将链表的后半部分翻转后,再从链表中间结点开始,与链头两两相比较,若不相同,则返回false
bool isPalindrome(struct ListNode* head) { if(head == NULL) return true; struct ListNode* dummy = (struct ListNode*)malloc(sizeof(struct ListNode)); dummy->next = head; struct ListNode *p = dummy, *q = dummy; while(q != NULL && q->next != NULL){ p = p->next; q = q->next->next; } //将链表从中间断开 q指向后半部分的头部 p指向前半部分尾部 q = p->next; p->next = NULL; //将后半部分翻转 while(q != NULL){ struct ListNode* tmp = q->next; q->next = p->next; p->next = q; q = tmp; } //前后开始两两比较 q = p->next; p = dummy->next; while(q != NULL){ if(p->val != q->val) return false; p = p->next; q = q->next; } return true;}
leetcode-21-合并两个有序链表
1.迭代,不构造新节点
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) { if(list1 == NULL || list2 == NULL) return list1 != NULL ? list1 : list2; struct ListNode* dummy = (struct ListNode*)malloc(sizeof(struct ListNode)); struct ListNode *pre, *p, *q; pre = dummy; p = list1; q = list2; while(p != NULL && q != NULL){ if(p->val val){ pre->next =p; pre =pre->next; p = p->next; } else if(p->val > q->val){ pre->next = q; pre = pre->next; q = q->next; } } if(p != NULL){ pre->next = p; } if(q != NULL){ pre->next = q; } return dummy->next;}
2.递归,不构造新节点
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) { if(list1 == NULL) return list2; if(list2 == NULL) return list1; if(list1->val val){ list1->next = mergeTwoLists(list1->next,list2); return list1; }else{ list2->next = mergeTwoLists(list1,list2->next); return list2; }}
3.迭代,构造新节点
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) { struct ListNode* dummy = (struct ListNode*)malloc(sizeof(struct ListNode)); dummy->next =NULL; struct ListNode *p = list1, *q = list2, *pre = dummy; while(p != NULL && q != NULL){ struct ListNode* cur = (struct ListNode*)malloc(sizeof(struct ListNode)); if(p->val val){ cur->val = p->val; p = p->next; }else{ cur->val = q->val; q = q->next; } pre->next = cur; cur->next = NULL; pre = cur; } pre->next = p != NULL ? p : q; return dummy->next;}
leetcode-25-k个一组翻转链表
struct ListNode* move(struct ListNode* node, int n){ while(node != NULL && n > 0){ node = node->next; n--; } return node;}struct ListNode* reverseKGroup(struct ListNode* head, int k) { struct ListNode *p, *q, *pre, *tmp, *link; bool flag = true; struct ListNode* dummy = (struct ListNode*)malloc(sizeof(struct ListNode)); dummy->next = head; p = q = link = dummy->next; while(q != NULL){ q = move(q,k-1); if(q == NULL) break; pre = q->next; while(pre != q){ tmp = p->next; p->next = pre; pre = p; p = tmp; } if(flag){ dummy->next = q; flag = false; }else{ link->next = q; } link = q; link = move(link,k-1); q = p; } return dummy->next;}
2.k一组翻转
3.用栈
leetcode-2-两数相加
考虑以下情况:
1.list1 比 list2 长 list2相加完后仍有进位
2.list2 比 list1 长 list1相加完后仍有进位
3.list1 和 list2 一样长,相加完后仍有进位
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) { int count; struct ListNode *p, *q, *pre; struct ListNode *dummy = (struct ListNode*)malloc(sizeof(struct ListNode)); count = 0; p = l1, q = l2, pre = dummy; while(p != NULL || q != NULL){ struct ListNode *node = (struct ListNode*)malloc(sizeof(struct ListNode)); node->next = NULL; int n1 = p != NULL ? p->val : 0; int n2 = q != NULL ? q->val : 0; node->val = (n1 + n2 + count)%10; count = (n1 + n2 + count)/10; pre->next = node; pre = node; if(p != NULL){ p = p->next; } if(q != NULL){ q = q->next; } } if(count != 0){ struct ListNode *node = (struct ListNode*)malloc(sizeof(struct ListNode)); node->next = NULL; node->val = count; pre->next = node; } return dummy->next;}
leetcode-138-随机链表的复制
leetcode-148-排序链表
归并法
struct ListNode* middleNode(struct ListNode* head) { struct ListNode* pre = head; struct ListNode* slow = head; struct ListNode* fast = head; while (fast && fast->next) { pre = slow; slow = slow->next; fast = fast->next->next; } pre->next = NULL; return slow;}struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) { struct ListNode dummy; struct ListNode* cur = &dummy; while (list1 && list2) { if (list1->val val) { cur->next = list1; list1 = list1->next; } else { cur->next = list2; list2 = list2->next; } cur = cur->next; } cur->next = list1 ? list1 : list2; return dummy.next;}struct ListNode* sortList(struct ListNode* head) { if (head == NULL || head->next == NULL) { return head; } struct ListNode* head2 = middleNode(head); head = sortList(head); head2 = sortList(head2); return mergeTwoLists(head, head2);}
leetcode-23-合并k个升序链表
leetcode-146-LRU缓存
leetcode-543-二叉树的直径
一条路径的长度为该路径经过的节点数减一,所以求直径(即求路径长度的最大值)等效于求路径经过节点数的最大值减一。
而任意一条路径均可以被看作由某个节点为起点,从其左儿子和右儿子向下遍历的路径拼接得到
假设我们知道对于该节点的左儿子向下遍历经过最多的节点数 L (即以左儿子为根的子树的深度) 和其右儿子向下遍历经过最多的节点数 R (即以右儿子为根的子树的深度),那么以该节点为起点的路径经过节点数的最大值即为 L+R+1 。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
int getDeep(struct TreeNode* root, int* ans){ if(root == NULL) return 0; int left = getDeep(root->left,ans); int right = getDeep(root->right,ans); *ans = fmax(*ans,left+right+1); return fmax(left,right)+1;}int diameterOfBinaryTree(struct TreeNode* root) { int ans = 1; getDeep(root,&ans); return ans-1;}
leetcode-662-二叉树最大宽度
leetcode-124-二叉树最大路径和
leetcode-437-路径总和III
leetcode-230-二叉搜索树第k小元素
int kthSmallest(struct TreeNode* root, int k) { struct TreeNode** stk = (struct TreeNode**)malloc(sizeof(struct TreeNode*)*10000); int* res = (int*)malloc(sizeof(int)*10000); struct TreeNode* node = root; int stk_top = 0; int index = 0; while(node != NULL || stk_top > 0){ while(node != NULL){ stk[stk_top++] = node; node = node->left; } node = stk[--stk_top]; res[index++] = node->val; node = node->right; } return res[k-1];}
leetcode-144-二叉树展开为链表
void flatten(struct TreeNode* root) { struct TreeNode** stk = (struct TreeNode**)malloc(sizeof(struct TreeNode*)*10000); struct TreeNode** res = (struct TreeNode**)malloc(sizeof(struct TreeNode*)*10000); int stk_top, index; stk_top = 0, index = 0; struct TreeNode* node = root; while(node != NULL || stk_top > 0){ while(node != NULL){ stk[stk_top++] = node; res[index++] = node; node = node->left; } node = stk[--stk_top]; node = node->right; } for(int i = 0 ; i left = NULL; res[i]->right = NULL; } for(int i = 0 ; i right = res[i+1]; }}
leetcode-124-二叉树中最大路径和