15三數之和;1248統計「優美子數組」;23合併K個排序鏈表;42接雨水

給你一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出所有滿足條件且不重複的三元組。

注意:答案中不可以包含重複的三元組。

 

示例:

給定數組 nums = [-1, 0, 1, 2, -1, -4],

滿足要求的三元組集合爲:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

class Solution {//雙指針
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int nSize=nums.size();
        if(nSize<3)return {};
        sort(nums.begin(),nums.end());
        vector<vector<int>>res;
        for(int i=0;i<nSize-2;++i){
            if(i>0&&nums[i]==nums[i-1])continue;//去重
            int le=i+1,ri=nSize-1;
            while(le<ri)
                if(nums[i]+nums[le]+nums[ri]==0){
                    res.push_back(vector<int>{nums[i],nums[le],nums[ri]});
                    while(le<ri&&nums[le]==nums[le+1])++le;//去重
                    //while(le<ri&&nums[ri]==nums[ri-1])--ri;
                    ++le,--ri;
                }
                else if(nums[i]+nums[le]+nums[ri]>0)--ri;
                else ++le;
        }
        return res;
    }
};
class Solution {//把多數情況的條件語句放在前面,如a,b,出現情況較少的條件放最後else,如c,可大幅度提升執行速度
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int nSize=nums.size();
        if(nSize<3)return {};
        sort(nums.begin(),nums.end());
        vector<vector<int>>res;
        for(int i=0;i<nSize-2;++i){
            if(i>0&&nums[i]==nums[i-1])continue;
            int le=i+1,ri=nSize-1,target=-nums[i];
            while(le<ri)                
                if(nums[le]+nums[ri]>target)--ri;//a
                else if(nums[le]+nums[ri]<target)++le;//b
                else{//c
                    res.push_back(vector<int>{nums[i],nums[le],nums[ri]});
                    while(le<ri&&nums[le]==nums[le+1])++le;
                    //while(le<ri&&nums[ri]==nums[ri-1])--ri;
                    ++le,--ri;
                }
        }
        return res;
    }
};

給你一個整數數組 nums 和一個整數 k。

如果某個 連續 子數組中恰好有 k 個奇數數字,我們就認爲這個子數組是「優美子數組」。

請返回這個數組中「優美子數組」的數目。

 

示例 1:

輸入:nums = [1,1,2,1,1], k = 3
輸出:2
解釋:包含 3 個奇數的子數組是 [1,1,2,1] 和 [1,2,1,1] 。


示例 2:

輸入:nums = [2,4,6], k = 1
輸出:0
解釋:數列中不包含任何奇數,所以不存在優美子數組。


示例 3:

輸入:nums = [2,2,2,1,2,2,1,2,2,2], k = 2
輸出:16


 

提示:


    1 <= nums.length <= 50000
    1 <= nums[i] <= 10^5
    1 <= k <= nums.length

class Solution {
//left統計距離左邊第一個奇數之間偶數的個數+1
//right統計距離右邊第一個奇數之間偶數的個數+1
//oddIndex統計所有奇數的下標
public:
    int numberOfSubarrays(vector<int>& nums, int k) {
        int nSize=nums.size();
        vector<int>left(nSize,1),right(nSize,1),oddIndex;
        int resCount=0;
        for(int i=0,j=nSize-1,nLe=0,nRi=0;i<nSize;++i,--j){
            if(nums[i]&1)
                left[i]+=nLe,nLe=0,oddIndex.push_back(i);
            else
                ++nLe;
            if(nums[j]&1)
                right[j]+=nRi,nRi=0;
            else
                ++nRi;
        }
        if(oddIndex.size()<k)return 0;
        for(int i=0,j=k-1;j<oddIndex.size();++i,++j)
            resCount+=left[oddIndex[i]]*right[oddIndex[j]];
        return resCount;
    }
};
class Solution {//發現oddIndex[i]-oddIndex[i-1]的值可以直接當作left[i]的值和right[i-1]的值
public:
    int numberOfSubarrays(vector<int>& nums, int k) {
        int nSize=nums.size();
        vector<int>oddIndex;
        int resCount=0;
        oddIndex.push_back(-1);
        for(int i=0;i<nSize;++i)
            if(nums[i]&1)
                oddIndex.push_back(i);
        oddIndex.push_back(nSize);
        if(oddIndex.size()-2<k)return 0;
        for(int i=1,j=k;j<oddIndex.size()-1;++i,++j)
            resCount+=(oddIndex[i]-oddIndex[i-1])*(oddIndex[j+1]-oddIndex[j]);
        return resCount;
    }
};
class Solution {//官方解法
    vector<int> cnt;
public:
    int numberOfSubarrays(vector<int>& nums, int k) {
        int n = (int)nums.size();
        cnt.resize(n + 1, 0);
        int odd = 0, ans = 0;
        cnt[0] = 1;//最難最容易漏掉
        for (int i = 0; i < n; ++i) {
            odd += nums[i] & 1;//統計0~i中奇數的個數
            ans += odd >= k ? cnt[odd - k] : 0;//(0~i中的奇數個數-k)個奇數個數,即j+1~i中的奇數個數等於k 這樣的j有幾個
            cnt[odd] += 1;//同樣個數奇數的個數統計
        }
        return ans;
    }
};

合併 k 個排序鏈表,返回合併後的排序鏈表。請分析和描述算法的複雜度。

示例:

輸入:
[
  1->4->5,
  1->3->4,
  2->6
]
輸出: 1->1->2->3->4->4->5->6

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    vector<ListNode*> lists;
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if(lists.size()==0)return nullptr;
        if(lists.size()==1)return lists[0];
        this->lists=lists;
        return  helper(0,lists.size()-1); 
    }
    ListNode *helper(int le,int ri){//二分法歸併
        if(le>ri)return nullptr;
        if(le==ri)return lists[le];
        int mid=le+((ri-le)>>1);
        ListNode *left=helper(le,mid);
        ListNode *right=helper(mid+1,ri);
        ListNode *LN=new ListNode(0);
        ListNode *res=LN;
        while(left&&right)
            if(left->val<right->val)
                res->next=left,left=left->next,res=res->next;
            else
                res->next=right,right=right->next,res=res->next;
        if(left)
            res->next=left;
        if(right)
            res->next=right;
        res=LN->next;
        delete LN;
        return res;
    }
};
//方法二:priority_queue小頂堆+進一個元素出一個元素

給定 n 個非負整數表示每個寬度爲 1 的柱子的高度圖,計算按此排列的柱子,下雨之後能接多少雨水。

 

上面是由數組 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度圖,在這種情況下,可以接 6 個單位的雨水(藍色部分表示雨水)。 感謝 Marcos 貢獻此圖。

示例:

輸入: [0,1,0,2,1,0,1,3,2,1,2,1]
輸出: 6

class Solution {//方法一:尋找每一列的左右最高列,left[i],right[i]
//res+=min(left[i],right[i])-height[i];
public:
    int trap(vector<int>& height) {
        int hSize=height.size();
        if(hSize<3)return 0;
        vector<int>left(hSize,0),right(hSize,0);
        left[0]=height[0];
        right[hSize-1]=height[hSize-1];
        for(int i=1,j=hSize-2;i<hSize;++i,--j){
            left[i]=max(left[i-1],height[i]);
            right[j]=max(right[j+1],height[j]);
        }
        int res=0;
        for(int i=0;i<hSize;++i){
            res+=min(left[i],right[i])-height[i];
        }
        return res;
    }
};
//可節省一個數組開銷left/right
class Solution {
public:
    int trap(vector<int>& height) {
        int hSize=height.size();
        if(hSize<3)return 0;
        vector<int>right(hSize,0);
        right[hSize-1]=height[hSize-1];
        for(int j=hSize-2;j>=0;--j)
            right[j]=max(right[j+1],height[j]);
        int res=0,leftMax=height[0];
        for(int i=0;i<hSize;++i){
            leftMax=max(leftMax,height[i]);
            res+=min(leftMax,right[i])-height[i];
        }
        return res;
    }
};
class Solution {//方法二:雙指針一左一右,誰小誰走,
public:
    int trap(vector<int>& height) {
        int hSize=height.size();
        if(hSize<3)return 0;
        int res=0,leftMax=0,rightMax=0;
        int le=0,ri=hSize-1;
        while(le<ri){
            if(height[le]<height[ri]){
                if(height[le]>leftMax)
                    leftMax=height[le];
                else
                    res+=leftMax-height[le];
                ++le;    
            }
            else{
                if(height[ri]>rightMax)
                    rightMax=height[ri];
                else   
                    res+=rightMax-height[ri];
                --ri;
            }
        }
        return res;
    }
};
class Solution {//方法三:單調遞減棧,存的是下標
public:
    int trap(vector<int>& height) {
        int hSize=height.size();
        if(hSize<3)return 0;
        int res=0,curIndex=0;
        stack<int>s;
        while(curIndex<hSize){
            while(s.size()&&height[curIndex]>height[s.top()]){
                int temp=s.top();
                s.pop();
                if(s.size()==0)break;
                int diff=curIndex-s.top()-1;//最難點
                //curIndex對應右邊最大值,temp當前計算列,s.top()左邊最大值
                res+=diff*(min(height[s.top()],height[curIndex])-height[temp]);
            }
            s.push(curIndex++);
        }
        return res;
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章