LeetCode题解-01(二分、链表、数组)

目录

LeetCode题解

chap-1: 二分#

section1-1: 索引二分#

1、搜索旋转排序数组#

根据中点划分为两段有序性队列,使用二分可在logN复杂度下实现查找;

Copy
class Solution { public: int search(vector<int>& nums, int target) { int l = 0, r = nums.size() - 1; while(l < r){ int mid = (l + r + 1) >> 1; if(nums[mid] < nums[0]) r = mid-1; else l = mid; } int x = l; if(nums[x] < target || x+1<nums.size() && nums[x+1] > target) return -1; if(nums[0] <= target){ l = 0, r = x; }else if(nums[nums.size()-1] >= target && x+1 < nums.size()){ l = x + 1, r = nums.size() - 1; }else return -1; while(l < r){ int mid = (l + r + 1) >> 1; if(target < nums[mid]) r = mid - 1; else l = mid; } return nums[l] == target ? l : -1; } };

2、在排序数组中查找元素的第一个和最后一个位置#

两次二分查找区间界限

Copy
class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { if(nums.empty()) return {-1,-1}; int l = 0, r = nums.size() - 1; while(l < r){ int mid = l+r+1>>1; if(nums[mid] > target) r = mid - 1; else l = mid; // 需注意的是l断点只能保证<=target即最右侧点位置 } if(nums[l] != target) return {-1,-1}; int R = l; // zan cun l = 0; while(l < r){ int mid = l+r>>1; if(nums[mid] < target) l = mid + 1; else r = mid; // 同理r仅能保证>=target即nums[mid]==target时,下一轮mid还需向左 } if(nums[r] != target) return {R,R}; else return{r,R}; } };

3、搜索插入位置#

Copy
class Solution { public: int searchInsert(vector<int>& nums, int target) { int l = 0, r = nums.size()-1; while(l < r){ int mid = (l + r + 1)>> 1; if(nums[mid] > target) r = mid - 1; else l = mid; } if(nums[l] >= target) return l; // 需注意,l的位置可能为零 else return l+1; } };

4、搜索旋转排序数组 II#

两次二分示意图

Copy
class Solution { public: bool search(vector<int>& nums, int target) { int l = 0, r = nums.size() - 1; while(l<r && nums[l] == nums[r]) r--; if(l == r) return nums[l] == target; // 注意 find the least num int L = l,R = r; while(L < R){ int mid=(L+R)>>1; if(nums[mid] > nums[R]) L = mid + 1; else R = mid; } if(nums[R] <= target && target <= nums[r]){ l = R; r = r; }else {l = l; r = R-1;} // 确定查询区间 while(l < r){ int mid = l+r>>1; if(nums[mid] < target) l = mid + 1; else r = mid; } return nums[l] == target; } };

5、搜索二维矩阵#

Copy
class Solution { public: bool searchMatrix(vector<vector<int>>& matrix, int target) { int l = 0, r = matrix[0].size()-1; while(~r && l < matrix.size()){ if(matrix[l][r] < target) l++; else if(matrix[l][r] > target) r--; else return true; } return false; } };

6、寻找旋转排序数组中的最小值#

Copy
class Solution { public: int findMin(vector<int>& nums) { int l = 0, r = nums.size(); while(l<r){ int mid = l+r>>1; if(nums[mid] > nums[nums.size()-1]) l = mid + 1; else r = mid; } return nums[r]; } };

7、寻找旋转排序数组中的最小值 II#

Copy
class Solution { public: int findMin(vector<int>& nums) { int l = 0, r = nums.size()-1; while(l<r && nums[r] == nums[l]) r--; int x = r; while(l < r){ int mid = l+r>>1; if(nums[mid] > nums[x]) l = mid + 1; else r = mid; } return nums[r]; } };

8、寻找峰值#

另类二分

相邻值不相同可以包含上述三种情形,<一><二>通过单调性易判定,<三>通过mid处相邻元素关系决定峰值区间,若mid<mid+1则其中一个峰值应在mid左侧,反之在右侧,进而使问题分解】

Copy
class Solution { public: int findPeakElement(vector<int>& nums) { int l = 0, r = nums.size()-1; while(l < r){ int mid = l+r>>1; if(nums[mid] < nums[mid + 1]) l = mid + 1; else r = mid; } return r; } };

9、H 指数#

Copy
class Solution { public: bool check(vector<int>& cits, int h){ int n = 0; for(auto &it:cits){ if(it >= h) n++; if(n >= h) return true; } return false; } int hIndex(vector<int>& cits) { int l = 0, r = cits.size(); // h指数区间 while(l < r){ int mid = l+r+1>>1; if(check(cits,mid)) l = mid; else r = mid - 1; } return l; } };

10、275. H 指数 II#

Copy
class Solution { public: bool check(vector<int>& cits,int h){ return cits[cits.size() - h] >= h; } int hIndex(vector<int>& cits) { int l = 0, r = cits.size(); while(l < r){ int mid = l+r+1>>1; if(check(cits,mid)) l = mid; else r = mid-1; } return l; } };

11、第一个错误的版本#

Copy
// The API isBadVersion is defined for you. // bool isBadVersion(int version); class Solution { public: int firstBadVersion(int n) { long l = 1, r = n; while(l < r){ long mid = l+r>>1; if(!isBadVersion(mid)) l = mid+1; else r = mid; } return r; } };

12、寻找右区间#

Copy
class Solution { public: vector<int> findRightInterval(vector<vector<int>>& intervals) { vector<int> ans(intervals.size(),-1); for(auto i=0;i<intervals.size();i++) intervals[i].push_back(i); sort(intervals.begin(),intervals.end()); for(auto &it:intervals){ int l = 0, r = intervals.size()-1; while(l < r){ int mid = (l+r)>>1; if(intervals[mid][0] < it[1]) l = mid+1; // else r = mid; } ans[it[2]] = intervals[r][0] >= it[1] ? intervals[r][2] : -1; } return ans; } };

13、有序数组中的单一元素#

思路1、具备二分查找的性质是可以将区间一次划分为前后两组组内性质相同的子区间

二分使用

如上,为方便描述,在区间尾端增添新元素(与前一元素不同),可以分为两组:黑色组内偶数idx相邻的两个数相同,黄色组内偶数idx相邻两个数必不同,二者交接处第一个不同元素为待求值;

Copy
class Solution { public: int singleNonDuplicate(vector<int>& nums) { nums.push_back(nums.back()+1); int l = 0, r = nums.size() / 2 - 1; while(l < r){ int mid = l + r >> 1; if(nums[mid*2] == nums[mid*2+1]) l = mid+1; else r = mid; } return nums[r*2]; } };

思路2:

Copy
class Solution { public: int singleNonDuplicate(vector<int>& nums) { int l = 0, r = nums.size()-1; while(l < r){ int mid = l + r >> 1; if(mid%2)mid--; // 保证仅比较偶数idx开始的相邻元素 if(nums[mid] == nums[mid+1]) l = mid+2; else r = mid; } return nums[r]; } };

14、二分查找—模板题#

Copy
class Solution { public: int search(vector<int>& nums, int target) { int l = 0, r = nums.size()-1; while(l < r){ int mid = l+r+1>>1; if(nums[mid] > target) r = mid-1; else l = mid; } return nums[l] == target ? l : -1; } };

[Go Back~~](# LeetCode题解)

section1-2: 值域二分#

1、猜数字大小#

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

关于long、long long

Copy
//c语言中 sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)

64位Linux采用的是LP64模型,这意味着Long, Pointer都是8字节。32位Linux采用的是ILP32模型,也就是Int Long Pointer均为4字节。

long-long long不同平台差异

2、x 的平方根#

Copy
class Solution { public: int mySqrt(int x) { int l = 0, r = x; while(l < r){ int mid = (long)l+r+1>>1; if(mid > x / mid) r = mid-1; else l = mid; } return l; } };

3、有效的完全平方数#

Copy
class Solution { public: bool isPerfectSquare(int num) { if(1 == num) return true; int l = 1,r = num; while(l < r){ long mid = (long)l+r>>1; if(mid*mid == num) return true; if(mid * mid < num) l = mid+1; else r = mid; } return false; } };

4、寻找重复数#

解法1

Copy
class Solution { public: int check(vector<int>& nums,int l,int n){ int s = 0; for(auto &num:nums){ if(num <= n && num >= l) s++; if(s > n - l + 1) return s; } return s; } int findDuplicate(vector<int>& nums) { int l = 1, r = nums.size()-1; while(l < r){ int mid = l+r>>1; if(check(nums,l,mid) > mid-l+1) r = mid; else l = mid+1; } return r; } };

解法2

Copy
// 参考有环链表class Solution { public: int findDuplicate(vector<int>& nums) { int l = 0, r = 0; while(true){ l = nums[l]; r = nums[nums[r]]; if(l==r){ l = 0; while(l != r){ l = nums[l]; r = nums[r]; } return l; } } return -1; } };

5、有序矩阵中第 K 小的元素#

解法1:使用有限队列保证队列长度为k,注意prioirty_queue默认为大根堆

Copy
class Solution { public: int kthSmallest(vector<vector<int>>& matrix, int k) { priority_queue<int> q; for(int i = 0;i<matrix.size();i++){ for(int j = 0;j<matrix[0].size();j++){ if(q.size() < k) q.push(matrix[i][j]); else{ if(matrix[i][j] < q.top()){ q.push(matrix[i][j]); q.pop(); } } } } return q.top(); } };

解法2:利用数值二分思想,考虑矩阵中数值范围进行二分,仅用列递增特点时复杂度O(n2logL)其L为数值范围​;

行有序与列有序同时使用时可优化为:(OnlogL)

Copy
class Solution { public: int check(vector<vector<int>>&matrix, int target,int n){ int cnt = 0; for(int i = 0;i<n;i++){ for(int j = 0;j<n;j++){ if(matrix[i][j] <= target) cnt++; else break; // 仅利用列递增特点 } } return cnt; } // check可进一步优化 int check(vector<vector<int>>&matrix, int target,int n){ int cnt = 0; int row = n-1, col = 0; while(row >= 0 && col < n){ if(matrix[row][col] <= target){ col++; cnt+=row+1; }else row--; } return cnt; } int kthSmallest(vector<vector<int>>& matrix, int k) { int n = matrix.size(); int l = matrix[0][0], r = matrix[n-1][n-1]; while(l<r){ int mid = l+r>>1; if(check(matrix,mid,n) < k) l = mid+1; else r = mid; } return r; } };

6、分割数组的最大值#

Copy
class Solution { public: int check(vector<int>& nums,int t){ int tot = 0,cnt = 1; for(int i = 0;i<nums.size();i++){ if(tot + nums[i] > t){ cnt++; tot = nums[i]; }else tot += nums[i]; } return cnt; } int splitArray(vector<int>& nums, int m) { int l = 0, r = 0; for(int i = 0;i<nums.size();i++){ l = max(l,nums[i]); r += nums[i]; } while(l < r){ int mid = (long)l+r>>1; if(check(nums,mid) > m) l = mid+1; else r = mid; } return r; } };

7、爱吃香蕉的珂珂#

Copy
class Solution { public: int check(vector<int>& piles,int k){ int cnt = 0; for(auto pile:piles){ cnt += (int)(pile + k-1)/k; } return cnt; } int minEatingSpeed(vector<int>& piles, int h) { int l = 1,r = 0; for(auto &it:piles) r = max(it,r); while(l<r){ int mid = l+r>>1; if(check(piles,mid) > h) l = mid+1; else r = mid; } return r; } };

8、在 D 天内送达包裹的能力#

Copy
class Solution { public: int check(vector<int>& weights,int n){ int tot = 0,cnt = 1; for(auto &weight:weights){ if(tot + weight > n){ cnt++; // init = 1 tot = weight; }else tot+=weight; } return cnt; } int shipWithinDays(vector<int>& weights, int days) { int l = 0, r = 0; for(auto &weight:weights){ l = max(l,weight); r += weight; } while(l<r){ int mid = (long)l+r>>1; if(check(weights,mid) > days) l = mid+1; else r = mid; } return r; } };

9、制作 m 束花所需的最少天数#

Copy
class Solution { public: int check(vector<int>& nums, int d,int k){ int cnt = 0, tot = 0; for(auto &num:nums){ if(num <= d){ tot++; }else tot = 0; if(tot == k) cnt++,tot=0; } return cnt; } int minDays(vector<int>& nums, int m, int k) { if((long)m*k > nums.size()) return -1; int l = INT_MAX, r = 0; for(auto &num:nums){ l = min(l,num); r = max(r,num); } while(l<r){ int mid = (long)l+r>>1; if(check(nums,mid,k) < m) l = mid+1; else r = mid; } return check(nums,r,k) >= m ? r : -1; } };

10、两球之间的磁力#

Copy
class Solution { public: int check(vector<int>& pos,int len){ int cnt = 1, id = pos[0]; for(int i = 1;i<pos.size();i++){ if(pos[i] - id > len){ cnt++; id = pos[i]; } } return cnt; } int maxDistance(vector<int>& poss, int m) { sort(poss.begin(),poss.end()); int l = INT_MAX, r = poss[poss.size()-1] - poss[0]; for(int i = 1;i<poss.size();i++) l = min(l,poss[i] - poss[i-1]); while(l < r){ int mid = (long)l+r>>1; if(check(poss,mid) > m-1) l = mid+1; else r = mid; } return r; } };

11、小张刷题计划#

Copy
class Solution { public: int check(vector<int>& a, int t){ int cnt = 1, rest = t,maxx = -1; bool flag = true; for(int i = 0; i < a.size(); i++){ maxx = max(maxx,a[i]); if(rest >= a[i]) rest -= a[i]; else if(flag) flag = false,rest += maxx,i--; else cnt++, maxx = -1,flag = true, rest = t, i--; } return cnt; } int minTime(vector<int>& time, int m) { int n = time.size(); int l = 0, r = 0; for(int i = 0; i < n; i++) r += time[i]; while(l < r){ int T = l + r >> 1; if(check(time,T) <= m) r = T; else l = T+1; } return r; } };

[Go Back~~](# LeetCode题解)

chap-2: 链表#

1、两数相加#

Copy
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { auto dummy = new ListNode(-1), cur = dummy; int t = 0; while (l1 || l2 || t) { if (l1) t += l1->val, l1 = l1->next; if (l2) t += l2->val, l2 = l2->next; cur = cur->next = new ListNode(t % 10); t /= 10; } return dummy->next; } };

2、两数相加 II#

Copy
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* reverse(ListNode* l){ auto dummy = new ListNode(-1), head = dummy; while(l){ auto t = l->next; l->next = head->next; head->next = l; l = t; } return dummy->next; } ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { auto dummy = new ListNode(-1), head = dummy; int t = 0; l1 = reverse(l1); l2 = reverse(l2); while(l1 || l2 || t){ if(l1){t += l1->val;l1=l1->next;} if(l2){t += l2->val;l2=l2->next;} head->next = new ListNode(t%10); head = head->next; t/=10; } return reverse(dummy->next); } };

3、删除链表的倒数第 N 个结点#

Copy
class Solution { public: ListNode* removeNthFromEnd(ListNode* head, int n) { auto dummy = new ListNode(-1), temp = dummy; dummy->next = head; auto h1 = head, h2 = head; while(n){h2 = h2->next;n--;} while(h2){temp = temp->next; h1 = h1->next; h2 = h2->next;} temp->next = h1->next; return dummy->next; } };

4、合并两个有序链表#

Copy
class Solution { public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { if(!l1) return l2; if(!l2) return l1; auto dummy = new ListNode(-1), head = dummy; while(l1 && l2){ if(l1->val < l2->val){ head->next = l1; l1 = l1->next; head = head->next; }else{ head->next = l2; l2 = l2->next; head = head->next; } } if(l1) head->next = l1; if(l2) head->next = l2; return dummy->next; } };

5、合并K个升序链表#

Copy
class Solution { public: ListNode* merge2Lists(ListNode* l1, ListNode* l2) { ListNode *head = new ListNode(0); ListNode *cur = head; while (l1 != NULL && l2 != NULL) { if (l1 -> val < l2 -> val) { cur -> next = l1; l1 = l1 -> next; } else { cur -> next = l2; l2 = l2 -> next; } cur = cur -> next; } cur -> next = (l1 != NULL ? l1 : l2); return head -> next; } ListNode* mergeKLists(vector<ListNode*>& lists) { if (lists.size() == 0) return NULL; if (lists.size() == 1) return lists[0]; int mid = lists.size() / 2; vector<ListNode*> left = vector<ListNode*>(lists.begin(), lists.begin() + mid); vector<ListNode*> right = vector<ListNode*>(lists.begin() + mid, lists.end()); ListNode *l1 = mergeKLists(left); ListNode *l2 = mergeKLists(right); return merge2Lists(l1, l2); } };

6、两两交换链表中的节点#

交换示意

Copy
class Solution { public: ListNode* swapPairs(ListNode* head) { if(head == nullptr) return head; auto dummy = new ListNode(-1), temp = dummy; dummy->next = head; auto c1 = dummy, c2 = dummy; while(c1->next){ c1 = c1->next->next; c2 = c2->next; if(c1 == nullptr) break; c2->next = c1->next; c1->next = c2; temp->next = c1; c1 = c2; temp = c2; } return dummy->next; } };

7、K 个一组翻转链表#

Copy
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* reverseKGroup(ListNode* head, int k) { auto dummy = new ListNode(); dummy->next = head; for(auto p = dummy;;){ auto q = p; for(int i=0;i<k && q;i++) q = q->next; if(!q) break; auto a = p->next,b = a->next; for(int i=0;i<k-1;i++){ auto c = b->next; b->next = a; a = b; b = c; } auto c = p->next; p->next = a; c->next = b; p = c; } return dummy->next; } };

8、旋转链表#

交换示意图

Copy
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* rotateRight(ListNode* head, int k) { if(!head) return head; int cnt = 0; auto h = head; while(h){cnt++; h = h->next;} k = cnt - k%cnt; if(!k || k == cnt) return head; auto dummy = head; while(--k) head = head->next; auto t = dummy; dummy = head->next; head->next = nullptr; head = dummy; while(head->next) head = head->next; head->next = t; return dummy; } };

9、删除排序链表中的重复元素#

Copy
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* deleteDuplicates(ListNode* head) { if(head == nullptr) return nullptr; auto dummy = new ListNode(-1), temp = dummy; dummy->next = head; while(true){ while(head->next && head->val == head->next->val){ head->next = head->next->next; } temp->next = head; temp = temp->next; head = head->next; if(!head) break; } return dummy->next; } };

10、删除排序链表中的重复元素 II#

传递思路

Copy
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* deleteDuplicates(ListNode* cur) { if(cur == nullptr) return nullptr; auto dummy = new ListNode(-101), pre = dummy; pre->next = cur; while(true){ bool f = false; while(cur->next && cur->val == cur->next->val){ f = true; cur = cur->next; } if(f) pre->next = cur->next; else pre = pre->next; cur = cur->next; if(!cur) break; } return dummy->next; } };

11、分隔链表#

Copy
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* partition(ListNode* head, int x) { auto dummy1 = new ListNode(-1), h1 = dummy1; auto dummy2 = new ListNode(-1), h2 = dummy2; while(head){ if(head->val < x) { h1->next = head; h1 = head; head = head->next; h1->next = nullptr; }else{ h2->next = head; h2 = head; head = head->next; h2->next = nullptr; } } h1->next = dummy2->next; return dummy1->next; } };

12、反转链表#

Copy
class Solution { public: ListNode* reverseList(ListNode* head) { auto dummy = new ListNode(-1); while(head){ auto q = head->next; head->next = dummy->next; // 每次进入时 插入head后 继承head后信息 dummy->next = head; head = q; } return dummy->next; } };

13、反转链表 II#

传递关系

Copy
class Solution { public: ListNode* reverseBetween(ListNode* head, int left, int right) { if(left == right) return head; right = right - left + 1; auto dummy = new ListNode(-1), pre = dummy; dummy->next = head; while(--left) { pre = pre->next; head = head->next; } while(right--){ auto t = head->next; head->next = pre->next; pre->next = head; head = t; } while(pre != pre->next) pre = pre->next; pre->next = head; return dummy->next; } };

14、环形链表#

Copy
class Solution { public: bool hasCycle(ListNode *head) { auto dummy = new ListNode(-1); dummy->next = head; auto s = dummy, f = dummy; while(s->next && f->next){ s = s->next; if(f->next->next) f = f->next->next; else return false; if(s == f) return true; } return false; } };

15、环形链表 II#

释义图

释义:用 z​​​​​​ 表示从 c​​​​​​ 点顺时针走到 b​​​​​​ 的距离。则第一次相遇时second​​​​​​所走的距离是 x+(y+z)n+y​​​​​​, n​​​​​​ 表示圈数,同时 sceond​​​​​​ 走过的距离是 first​​​​​​ 的两倍,也就是 2(x+y)​​​​​​,所以我们有 x+(y+z)n+y=2(x+y)​​​​​​,所以x=(n1)×(y+z)+z​​​​​​,此处易知n1​​​​。那么我们让 second​​​​​​ 从c​​​​​​点开始走,走 x​​​​​​ 步,会恰好走到 b​​​​​​ 点;让 first​​​​​​ 从 a​​​​​​ 点开始走,走 x​​​​​​ 步,也会走到 b​​​​​​​点。

Copy
class Solution { public: ListNode *detectCycle(ListNode *head) { auto dummy = new ListNode(-1); dummy->next = head; auto s = dummy, f = dummy; while(s->next && f->next){ s = s->next; if(f->next->next) f = f->next->next; else return NULL; if(s == f){ s = dummy; while(s!=f){ s = s->next; f = f->next; } return s; } } return NULL; } };

16、重排链表#

Copy
class Solution { public: ListNode* reverse(ListNode* head){ auto dummy = new ListNode(-1), t = dummy; while(head){ auto temp = head->next; head->next = t->next; t->next = head; head = temp; } return dummy->next; } void reorderList(ListNode* head) { auto dummy = new ListNode(-1); dummy->next = head; auto s = dummy, f = dummy; while(s->next && f->next){ s = s->next; f = f->next->next; if(!f) break; } f = s->next; s->next = nullptr; s = head; f = reverse(f); while(s && f){ auto t = s->next; s->next = f; f = f->next; s->next->next = t; s = t; } } };

17、相交链表#

Copy
class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { int d1 = 0, d2 = 0; auto t1 = headA, t2 = headB; while(t1) d1++, t1 = t1->next; while(t2) d2++, t2 = t2->next; if(d1>d2){ t2 = headA, t1 = headB; }else t1 = headA, t2 = headB; int len = abs(d1 - d2); while(len--) t2 = t2->next; while(t1){ if(t1 == t2) return t1; else { t1 = t1->next; t2 = t2->next; } } return NULL; } };

18、移除链表元素#

Copy
class Solution { public: ListNode* removeElements(ListNode* head, int val) { auto dummy = new ListNode(-1), t = dummy; while(true){ if(!head) break; if(head->val == val) head = head->next; else t->next = head, head = head->next, t = t->next; } t->next = head; return dummy->next; } };

19、回文链表#

Copy
class Solution { public: ListNode* reverse(ListNode* head){ auto dummy = new ListNode(-1), t = dummy; while(head){ auto temp = head->next; head->next = t->next; t->next = head; head = temp; } return dummy->next; } bool isPalindrome(ListNode* head) { auto dummy = new ListNode(-1); dummy->next = head; auto s = dummy, f = dummy; while(s->next && f->next){ s = s->next; f = f->next->next; if(!f) break; } f = s->next; s->next = nullptr; s = head; f = reverse(f); while(f){ if(f->val != s->val) return false; f = f->next; s = s->next; } return true; } };

20、删除链表中的节点#

Copy
class Solution { public: void deleteNode(ListNode* node) { while(node && node->next){ node->val = node->next->val; auto t = node; node = node->next; if(node->next == NULL) t->next = NULL; } } };

21、奇偶链表#

Copy
class Solution { public: ListNode* oddEvenList(ListNode* head) { if(head == nullptr) return head; int cnt = 0; ListNode* odd=nullptr, *even=nullptr, *h = nullptr, *h1 = nullptr; while(head){ cnt++; auto t = head->next; if(cnt % 2){ if(!odd) {odd = head; h = odd;} else odd->next = head, odd = odd->next; odd->next = nullptr; }else{ if(!even) {even = head; h1 = even;} else even->next = head, even = even->next; even->next = nullptr; } head = t; } odd->next = h1; return h; } };

22、设计链表#

Copy
struct node { int val; node* prev; node* next; node(int v, node* p, node* n) : val(v), prev(p), next(n) {} }; class MyLinkedList { public: /** Initialize your data structure here. */ MyLinkedList() { head = NULL; tail = NULL; } /** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */ int get(int index) { node* p = head; for (int i = 1; i <= index && p; ++i) p = p->next; return p ? p->val : -1; } /** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */ void addAtHead(int val) { node* h = head; head = new node(val, NULL, h); if (h) h->prev = head; else tail = head; } /** Append a node of value val to the last element of the linked list. */ void addAtTail(int val) { node* t = tail; tail = new node(val, t, NULL); if (t) t->next = tail; else head = tail; } /** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */ void addAtIndex(int index, int val) { // add at head if (index == 0) { addAtHead(val); return; } int len = 0; for (auto p = head; p; p = p->next) len++; if (index > len) return; // add at tail if (index == len) { addAtTail(val); return; } // add at the middle of list auto p = head; for (int i = 1; i <= index && p; ++i) p = p->next; auto q = p->prev; q->next = new node(val, q, p); p->prev = q->next; } /** Delete the index-th node in the linked list, if the index is valid. */ void deleteAtIndex(int index) { if (index == 0) { head = head->next; if(head) head->prev = NULL; return; } auto p = head; for (int i = 1; i <= index && p; ++i) p = p->next; // out of bound if (!p) return; // p is the tail if (!p->next) { auto q = p->prev; if (q) q->next = NULL; tail = q; } else { auto q = p->prev; p = p->next; if (q) q->next = p, p->prev = q; } } private: node* head; node* tail; };

23、链表的中间结点#

Copy
class Solution { public: ListNode* middleNode(ListNode* head) { auto dummy = new ListNode(-1), s = dummy, f = dummy; dummy->next = head; while(f){ if(!f->next) break; s = s->next; f = f->next->next; } if(f) s = s->next; return s; } };

[Go Back~~](# LeetCode题解)

chap-3: 数组#

1、有效的数独#

Copy
class Solution { public: bool isValidSudoku(vector<vector<char>>& board) { vector<bool> f(10,false); for(int i = 0;i<9;i++){ f = vector<bool>(10,false); for(int j = 0;j<9;j++){ if(board[i][j] == '.')continue; else if(f[board[i][j] - '0']) return false; else f[board[i][j] - '0'] = true; } } for(int i = 0;i<9;i++){ f = vector<bool>(10,false); for(int j = 0;j<9;j++){ if(board[j][i] == '.')continue; else if(f[board[j][i] - '0']) return false; else f[board[j][i] - '0'] = true; } } for(auto i = 0;i<9;i+=3){ for(auto j = 0;j<9;j+=3){ f = vector<bool>(10,false); for(auto m = 0;m<3;m++){ for(auto n = 0;n<3;n++){ if(board[i+m][j+n] == '.') continue; else if(f[board[i+m][j+n] - '0']) return false; else f[board[i+m][j+n] - '0'] = true; } } } } return true; } };

2、旋转图像#

Copy
class Solution { public: void rotate(vector<vector<int>>& matrix) { int n = matrix.size(); for(int i = 0;i<n/2;i++){ for(int j = 0;j<n;j++){ swap(matrix[i][j],matrix[n-i-1][j]); } } for(int i=0;i<n;i++){ for(int j=0;j<i;j++){ swap(matrix[i][j],matrix[j][i]); } } } };

3、合并区间#

Copy
class Solution { public: vector<vector<int>> merge(vector<vector<int>>& intervals) { vector<vector<int>> ans; sort(intervals.begin(),intervals.end()); int end = -1,start = -1; for(auto &inter:intervals){ if(inter[0] > end) { if(end != -1) ans.push_back({start,end}); start = inter[0]; end = inter[1]; } else { end = max(end,inter[1]); } } ans.push_back({start,end}); return ans; } };

4、插入区间#

Copy
class Solution { public: vector<vector<int>> insert(vector<vector<int>>& a, vector<int>& b) { vector<vector<int>> res; int k = 0; while (k < a.size() && a[k][1] < b[0]) res.push_back(a[k++]); // 左边完全没交集的部分 if (k < a.size()) { b[0] = min(b[0], a[k][0]); while (k < a.size() && a[k][0] <= b[1]) b[1] = max(b[1], a[k++][1]); } // 处理交集部分 res.push_back(b); while (k < a.size()) res.push_back(a[k++]); return res; } };

5、矩阵置零#

解法1:采用O(m+n)​空间复杂度

Copy
class Solution { public: void setZeroes(vector<vector<int>>& matrix) { set<int> row, col; for(int i = 0;i<matrix.size();i++){ for(int j = 0;j<matrix[0].size();j++){ if(matrix[i][j] == 0) row.insert(i), col.insert(j); } } for(auto &r:row){ for(int j = 0;j<matrix[0].size();j++) matrix[r][j] = 0; } for(auto &c:col){ for(int j = 0;j<matrix.size();j++) matrix[j][c] = 0; } } };

解法2: 采用O(1)​空间复杂度— tips:使用第一行与第一列记录分别记录对应的行是否需要置零

1、开辟两个变量记录第一行和第一列是否有0。
2、遍历整个矩阵,用矩阵的第一行和第一列记录对应的行和列是否有0。
3、把含有0的行和列都置成0。

Copy
class Solution { public: void setZeroes(vector<vector<int>>& matrix) { if (matrix.empty()) return; int col = 1, row = 1; for (int i = 0; i < matrix.size(); i ++ ) if (!matrix[i][0]) col = 0; for (int i = 0; i < matrix[0].size(); i ++ ) if (!matrix[0][i]) row = 0; for (int i = 1; i < matrix.size(); i ++ ) for (int j = 1; j < matrix[0].size(); j ++ ) if (!matrix[i][j]) { matrix[i][0] = 0; matrix[0][j] = 0; } for (int i = 1; i < matrix.size(); i ++ ) if (!matrix[i][0]) for (int j = 1; j < matrix[0].size(); j ++ ) matrix[i][j] = 0; for (int i = 1; i < matrix[0].size(); i ++ ) if (!matrix[0][i]) for (int j = 1; j < matrix.size(); j ++ ) matrix[j][i] = 0; if (!col) for (int i = 0; i < matrix.size(); i ++ ) matrix[i][0] = 0; if (!row) for (int i = 0; i < matrix[0].size(); i ++ ) matrix[0][i] = 0; } };

6、多数元素—摩尔投票法#

Copy
class Solution { public: int majorityElement(vector<int>& nums) { int ans = INT_MAX,cnt=0; for(auto &num:nums){ if(num == ans) cnt++; else { cnt--; if(cnt <= 0) ans = num, cnt = 1; } } return ans; } };

7、旋转数组#

Copy
class Solution { public: void rotate(vector<int>& nums, int k) { k %= nums.size(); reverse(nums.begin(), nums.end()); reverse(nums.begin(), nums.begin() + k); reverse(nums.begin() + k, nums.end()); } };

8、求众数 II—摩尔投票#

Copy
class Solution { public: vector<int> majorityElement(vector<int>& nums) { int a = INT_MAX, b = INT_MAX, cnt1 = 0, cnt2 = 0; for(auto &num:nums){ // 摩尔投票确定两个候选数 if(a == num) cnt1++; else if(b == num) cnt2++; else if(!cnt1){ cnt1++; a = num; }else if(!cnt2){ cnt2++; b = num; }else{ cnt1--; cnt2--; } } cnt1 = cnt2 = 0; for(auto &num:nums){ // 统计候选数实际数量 if(num == a) cnt1++; if(num == b) cnt2++; } vector<int> ans; if(cnt1 > (nums.size() / 3)) ans.push_back(a); if(cnt2 > (nums.size() / 3)) ans.push_back(b); return ans; } };

9、除自身以外数组的乘积#

Copy
class Solution { public: vector<int> productExceptSelf(vector<int>& nums) { vector<int> ans = vector<int>(nums.size(),1); for(int i=1;i<nums.size();i++){ ans[i] = nums[i-1]*ans[i-1]; } for(int i = nums.size()-2, k = 1;i>=0;i--){ k*=nums[i+1]; ans[i] = k*ans[i]; } return ans; } };

10、区域和检索 - 数组不可变#

Copy
class NumArray { public: vector<int> s; NumArray(vector<int>& nums) { for(int i = 0;i<nums.size();i++){ if(s.empty()) s.push_back(nums[i]); else s.push_back(s.back() + nums[i]) ; } } int sumRange(int left, int right) { if(!left) return s[right]; else return s[right] - s[left-1]; } };

11、二维区域和检索 - 矩阵不可变#

Copy
class NumMatrix { public: vector<vector<int>> s; NumMatrix(vector<vector<int>>& matrix) { int m = matrix.size(), n = matrix[0].size(); s = vector<vector<int>>(m+1,vector<int>(n+1,0)); for(int i = 0;i<m;i++) for(int j = 0;j<n;j++) s[i+1][j+1] = - s[i][j] + s[i+1][j] + s[i][j+1] + matrix[i][j]; } int sumRegion(int row1, int col1, int row2, int col2) { return s[row2+1][col2+1] + s[row1][col1] - s[row2+1][col1] - s[row1][col2+1]; } };

12、打乱数组—洗牌算法#

Copy
class Solution { public: vector<int> a; Solution(vector<int>& nums) { a = nums; } /** Resets the array to its original configuration and return it. */ vector<int> reset() { return a; } /** Returns a random shuffling of the array. */ vector<int> shuffle() { auto b = a; int n = b.size(); for(int i = 0;i<n;i++){ swap(b[i],b[i + rand()%(n - i)]); } return b; } };

13、等差数列划分#

acw-单个len内求和公式解释

Copy
class Solution { public: int numberOfArithmeticSlices(vector<int>& nums) { int n = nums.size(); if(n < 3) return 0; for(int i = nums.size()-1;i;i--) nums[i] = nums[i] - nums[i-1]; int ans = 0; for(int i = 1;i<nums.size();i++){ int j = i; while(j<nums.size() && nums[i] == nums[j]) j++; int k = j-i; ans += k*(k-1)/2; // 相同差分点数共:j-i=k个,对应num数为k+1,至少连续三个组成等差数列,因此对起点k+1位置,终点可选为k-1个,依次类推:k-1 + k-2 + k-3 + …… + 1 i = j-1; } return ans; } };

14、甲板上的战舰#

代码示意图

Copy
class Solution { public: int countBattleships(vector<vector<char>>& board) { int ans = 0; for(int i = 0;i<board.size();i++){ for(int j = 0;j<board[0].size();j++){ if(i && board[i-1][j] == 'X') continue; // 上侧出现 else if(j && board[i][j-1] == 'X') continue; // 左侧出现 else if(board[i][j] == 'X') ans++; } } return ans; } };

15、数组中重复的数据—内卷法#

Copy
class Solution { public: vector<int> findDuplicates(vector<int>& nums) { vector<int> ans; for(int i = 0;i<nums.size();i++){ int idx = abs(nums[i])-1; if(nums[idx] < 0) ans.push_back(abs(nums[i])); else nums[idx] = -nums[idx]; } return ans; } };

16、找到所有数组中消失的数字—内卷法#

Copy
class Solution { public: vector<int> findDisappearedNumbers(vector<int>& nums) { vector<int> ans; for(int i = 0;i<nums.size();i++){ int idx = abs(nums[i])-1; if(nums[idx]<0)continue; else nums[idx] = -nums[idx]; } for(int i = 0;i<nums.size();i++){ if(nums[i] > 0) ans.push_back(i+1); } return ans; } };

17、最小操作次数使数组元素相等#

1、每次令n1​​​个元素的值加 1​​​,相当于对一个元素减 1​​​。
2、故只需要找到最小的元素值 min_x​​​,让其他大于它的元素减少到 min_x​​​。
3、具体地,让所有元素的总和 tot 减去 nmin_x

Copy
class Solution { public: int minMoves(vector<int>& nums) { return accumulate(nums.begin(), nums.end(), 0) - nums.size() * *min_element(nums.begin(), nums.end()); } };

18、数组拆分 I#

Copy
class Solution { public: int arrayPairSum(vector<int>& nums) { sort(nums.begin(),nums.end()); int ans = 0; for(auto i = 0;i<nums.size();i+=2){ ans += nums[i]; } return ans; } };

19、数组嵌套#

Copy
class Solution { public: int arrayNesting(vector<int>& nums) { int res = 0; for(int i = 0;i<nums.size();i++){ if(nums[i] < 0) continue; // 搜索过的idx不需要再重新搜 int cur = 1,idx = nums[i]; nums[i] = -1; while(nums[idx] >= 0) { int pre = idx; idx = nums[idx]; nums[pre] = -1; cur ++; } res = max(res,cur); } return res; } };

20、重塑矩阵#

Copy
class Solution { public: vector<vector<int>> matrixReshape(vector<vector<int>>& mat, int r, int c) { int m = mat.size(), n = mat[0].size(); if(m*n != r*c) return mat; vector<vector<int>> ans = vector<vector<int>>(r,vector<int>(c,0)); for(int i = 0;i<m;i++){ for(int j = 0;j<n;j++){ int k = (i*n+j); ans[k/c][k%c] = mat[i][j]; } } return ans; } };

21、去掉最低工资和最高工资后的工资平均值#

Copy
class Solution { public: double average(vector<int>& salary) { int h = -1, l = -1; double res = 0; for(auto &s:salary){ if(h == -1 && l == -1) h = s, l = s; res += s; if(h < s) h = s; else if(l > s) l = s; } res = res - h - l; return res/(salary.size()-2); } };

22、存在连续三个奇数的数组#

Copy
class Solution { public: bool threeConsecutiveOdds(vector<int>& arr) { int n = arr.size(); for (int i = 0; i <= n - 3; ++i) { if ((arr[i] & 1) & (arr[i + 1] & 1) & (arr[i + 2] & 1)) { return true; } } return false; } };

23、使数组互补的最少操作次数#

1、对于一对数$ nums(i),nums(j)l=min(nums(i),num(j))mid=nums(i)+nums(j)r=max(nums(i)+nums(j))+limit2[2,l+1),[l+1,mid),[mid,mid+1),[mid+1,r+1),[r+1,2∗limit+1)3 s$ 在第一段和最后一段区间中,则这对数字需要两次操作,如果在第二或者四段区间中,则这对数字需要一次操作,如果在第三段(mid​)区间中,则不需要操作
4、预处理每对数字,利用差分数组的思想,在分界线插入变更值,最后求前缀和就是 [2,2limit]​​上的答案。

Copy
class Solution { public: int minMoves(vector<int>& nums, int limit) { const int n = nums.size(); vector<int> sum(limit * 2 + 2, 0); for (int i = 0, j = n - 1; i < j; i++, j--) { sum[2] += 2; sum[min(nums[i], nums[j]) + 1] -= 2; sum[min(nums[i], nums[j]) + 1] += 1; sum[nums[i] + nums[j]] -= 1; sum[nums[i] + nums[j] + 1] += 1; sum[max(nums[i], nums[j]) + limit + 1] -= 1; sum[max(nums[i], nums[j]) + limit + 1] += 2; } int ans = n; for (int i = 2; i <= 2 * limit; i++) { sum[i] += sum[i - 1]; ans = min(ans, sum[i]); } return ans; } };

[Go Back~~](# LeetCode题解)

posted @   SrtFrmGNU  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示
CONTENTS