給你一個包含 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;
}
};