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

目录

LeetCode题解

chap-1: 二分

section1-1: 索引二分

1、搜索旋转排序数组

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

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、在排序数组中查找元素的第一个和最后一个位置

两次二分查找区间界限

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、搜索插入位置

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

两次二分示意图

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、搜索二维矩阵

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、寻找旋转排序数组中的最小值

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

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左侧,反之在右侧,进而使问题分解】

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 指数

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

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、第一个错误的版本

// 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、寻找右区间

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相邻两个数必不同,二者交接处第一个不同元素为待求值;

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:

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、二分查找—模板题

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、猜数字大小

/** 
 * 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

//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 的平方根

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、有效的完全平方数

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

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

// 参考有环链表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默认为大根堆

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(n^2logL)\)其L为数值范围​;

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

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、分割数组的最大值

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、爱吃香蕉的珂珂

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 天内送达包裹的能力

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 束花所需的最少天数

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、两球之间的磁力

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、小张刷题计划

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、两数相加

/**
 * 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

/**
 * 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 个结点

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、合并两个有序链表

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个升序链表

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、两两交换链表中的节点

交换示意

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 个一组翻转链表

/**
 * 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、旋转链表

交换示意图

/**
 * 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、删除排序链表中的重复元素

/**
 * 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

传递思路

/**
 * 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、分隔链表

/**
 * 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、反转链表

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

传递关系

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、环形链表

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=(n−1)×(y+z)+z\)​​​​​​,此处易知\(n\geq1\)​​​​。那么我们让 \(second\)​​​​​​ 从\(c\)​​​​​​点开始走,走 \(x\)​​​​​​ 步,会恰好走到 \(b\)​​​​​​ 点;让 \(first\)​​​​​​ 从 \(a\)​​​​​​ 点开始走,走 \(x\)​​​​​​ 步,也会走到 \(b\)​​​​​​​点。

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、重排链表

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、相交链表

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、移除链表元素

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、回文链表

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、删除链表中的节点

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、奇偶链表

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、设计链表

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、链表的中间结点

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、有效的数独

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、旋转图像

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、合并区间

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、插入区间

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)\)​空间复杂度

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。

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、多数元素—摩尔投票法

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、旋转数组

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—摩尔投票

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、除自身以外数组的乘积

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、区域和检索 - 数组不可变

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、二维区域和检索 - 矩阵不可变

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、打乱数组—洗牌算法

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内求和公式解释

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、甲板上的战舰

代码示意图

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、数组中重复的数据—内卷法

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、找到所有数组中消失的数字—内卷法

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、每次令$ n - 1$​​​个元素的值加 \(1\)​​​,相当于对一个元素减 \(1\)​​​。
2、故只需要找到最小的元素值 \(min\_x\)​​​,让其他大于它的元素减少到 \(min\_x\)​​​。
3、具体地,让所有元素的总和 \(tot\) 减去 \(n * min\_x\)

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

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、数组嵌套

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、重塑矩阵

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、去掉最低工资和最高工资后的工资平均值

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、存在连续三个奇数的数组

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))+limit\(​​。 2、这三个分界点可以分为五段区间:\)[2,l+1),[l+1,mid),[mid,mid+1),[mid+1,r+1),[r+1,2∗limit+1)\(​。 3、如果最终的加和\) s$ 在第一段和最后一段区间中,则这对数字需要两次操作,如果在第二或者四段区间中,则这对数字需要一次操作,如果在第三段(\(等于 mid\)​)区间中,则不需要操作
4、预处理每对数字,利用差分数组的思想,在分界线插入变更值,最后求前缀和就是 \([2,2*limit]\)​​上的答案。

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 @ 2022-02-14 01:04  SrtFrmGNU  阅读(29)  评论(0编辑  收藏  举报