球球速刷LC之数组 三轮

z字打印333

观察到每个元素的行从0–>nrow。再从nRow–>0
因此可以使用一个字符串数组,按照行索引的变化规律将元素填充到数组中,最终统一输出。

class Solution {
public:
    string convert(string s, int numRows) {
        vector<string>vec(numRows);
        if(numRows<=1) return s;//注意对numRows过小的处理
        //行数在0-numRows-1之间来回变换
        int i=0;
        while(i<s.size()){
            //打印竖着的位置
            for(int row=0;row<numRows&&i<s.size();++row,++i){
                vec[row].push_back(s[i]);
            }
            //打印斜向上
            for(int row=numRows-2;row>=1&&i<s.size();--row,++i){
                vec[row].push_back(s[i]);
            }
        }
        string res;
        for(auto i:vec)res+=i;
        
        return res;        
    }
};
旋转矩阵333

技巧是先将矩阵按对角线交换,在翻转每一行

void swap(int &a , int &b)
{
    int temp = a;
    a =b;
    b = temp;
}

void reverse(vector<int>&array)
{
    int i = 0;
    int j =array.size()-1;
    while(i < j)
    {
        swap(array[i] , array[j]);
        ++i;
        --j;
    }
}

class Solution {
public:
    void rotate(vector<vector<int> > &matrix) {
        if(matrix.size() <= 1) return;
        
        int temp = 0;
        for(int i = 0 ; i < matrix.size() ;++i)//对矩阵按对角线交换
        {
            for(int j = i+1 ; j < matrix.size() ; ++j)
            {
              swap(matrix[i][j] , matrix[j][i]);
            }
        }
        //翻转矩阵每一行
        for_each(matrix.begin() , matrix.end(),[&](vector<int>&array){reverse(array);});
        
    }
};
螺旋打印矩阵333

以每一圈所打印的矩形为一次。则将矩形的左上角顶点(ntop,nleft)、右下角顶点(nBottom,nRight)作为当前矩形的边界。
以顺时针打印,注意在打印矩阵的下边和左边时,需要nbottom<ntop 和nLeft<nRight以防止矩阵仅仅只有一行或者仅仅只有一列时造成的重复打印。

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> result;
        if(matrix.size() == 0 ) return result;
        //矩形左上角顶点
        int nLeft = 0;
        int nTop = 0;
        //矩形右下角顶点
        int nRight = matrix[0].size()-1;
        int nBottom = matrix.size()-1;
        //循环条件是矩形的成立条件
        while(nLeft <= nRight && nTop <= nBottom)
        {
           //打印上边
            for(int i = nLeft ; i <= nRight ; ++i) result.push_back(matrix[nTop][i]);
            //打印右边
            for(int i = nTop+1 ; i<=nBottom; ++i) result.push_back(matrix[i][nRight]);
            //打印下边,注意防止和上边重复
            for(int i = nRight-1 ; i>= nLeft&&nBottom>nTop ;--i) result.push_back(matrix[nBottom][i]);//注意仅有一行时需要判断nBottom 与nTop                                                                                                      //防止重复遍历
            //打印左边,注意和右边重复
            for(int i = nBottom-1 ; i>= nTop+1&&nLeft<nRight ;--i) result.push_back(matrix[i][nLeft]);
            //更新当前矩形顶点,使其向内收缩
            ++nLeft;
            ++nTop;
            --nRight;
            --nBottom;
        }
        return result;
        
    }
};
螺旋打印2

思路与1相同。

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
         vector<vector<int>> matrix(n,vector<int>(n,0));
         
        if(matrix.size() == 0 ) return matrix;
        
        int nLeft = 0;
        int nRight = matrix[0].size()-1;
        int nTop = 0;
        int nBottom = matrix.size()-1;
        long long k=1;
        
        while(nLeft <= nRight && nTop <= nBottom)
        {
            for(int i = nLeft ; i <= nRight ; ++i){
                 matrix[nTop][i] =k;
                 ++k;
            }
            
            for(int i = nTop+1 ; i<=nBottom; ++i) {
                
               matrix[i][nRight] = k;
               ++k;
            }
            
            for(int i = nRight-1 ; i>= nLeft&&nBottom>nTop ;--i) {
                matrix[nBottom][i] =k;//注意仅有一行时需要判断nBottom 与nTop
                ++k;
            }
                                                                                                      //防止重复遍历
            
            for(int i = nBottom-1 ; i>= nTop+1&&nLeft<nRight ;--i) 
            {
                matrix[i][nLeft] =k;
                ++k;
            }
            
            ++nLeft;
            --nRight;
            ++nTop;
            --nBottom;
        }
        return matrix;
    }
};
去除有序数组中重复元素333
最长连续的子序列333

使用哈希表

class Solution {
public:
	int longestConsecutive(vector<int>& nums) {
		if (nums.size() <= 1)  return nums.size();
        unordered_set<int> hashSet;
        
        for_each(nums.begin() , nums.end() , [&](int a){hashSet.insert(a) ;}) ;
        
        
        int currNum = 0;
        int result = 0;
        for(auto it = hashSet.begin() ; it != hashSet.end() ;)
        {
                currNum = 1;
                auto tempIt = it;
               
                int next = (*it)+1;
                while( (tempIt = hashSet.find( next )) != hashSet.end() )
                {
                    hashSet.erase(tempIt) ;
                    ++currNum ;
                    ++next;
                }
                
                next = (*it) - 1;
                 while( (tempIt = hashSet.find( next )) != hashSet.end() )
                {
                    hashSet.erase(tempIt) ;
                    ++currNum ;
                    --next;
                }
                tempIt = it;
                ++it;
                hashSet.erase(tempIt) ; 
                if(currNum > result) result = currNum ;
                
                currNum = 0;
        }
        return result;
	}
};
下一个排列333

阅读文章 下一个排列解题报告

第一个缺少的正数333

整体思路是物归原处
对于给定的n个整数{a1 a2 … aN}
如果里面最小的正数 amin >n 则,缺少的第一个正数就是1
所以我们如果把{a1 a2 … aN} 里面小于n的正数ai 放在数组的第ai个位置。那么最后数组里
第一个 其位置和该位置的数字不同的,就是第一个缺失的正数。
例子
阶段1 依次检查每个数字,让其物归原处

迭代\位置12345678解析
<1>-3781291112-3不是正数,跳过
<2>-37812911127不在自己位置上,第7个位置上是11
<3>-3118129712把7放到第7个位置,11被调换回来继续从当前位置检查。11超过最大位置,跳过
<4>-31181297128不在自己位置,同样物归原处
<5>-3111212978检查12,12超过最大位置,跳过
<6>-31112129781不在自己位置,物归原处
<7>11112 -32978-3不是正数,跳过
<8>11112-3 29782不在自己位置,物归原处
<9>1212-31197811超过最大位置,跳过
<10>1212-3119789超过最大位置,跳过
<11>1212-311978剩下数字都在自己位置上,结束物归原处阶段

阶段2 得到第一个不是物归原处的位置

迭代\位置12345678解析
检查1212-311978第3个位置是第一个没有物归原处的位置

因此第一个缺失的正数是3

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        for(int i=0;i<nums.size();){
            //当前数字大小在数组位置范围内,且没有物归原处
            if(nums[i]!=(i+1) && nums[i]>0 && nums[i]<=nums.size()){
               //如果目标位置没有物归原处,则交换二者。
                if(nums[nums[i]-1] != nums[i]){
                    swap(nums[nums[i]-1],nums[i]);
                    continue; //此时需要继续在当前位置检查,所以索引不递增
                }
            }
            ++i; //对于不是正数或者超过数组范围的数直接跳过
        }
        int i=0;
        //最后第一个没有物归原处的位置就是第一个缺失的正数
        while(i<nums.size() && nums[i]==(i+1))++i;
        
        return i+1;
    }
};
合并区间333

设空集A,依次将输入给定集合B里的区间元素i与A中所有元素判断,是否能与A中某区间j合并,
若能,则将合并产生的新区间继续放入B中,且将j从A内删除;
若不能合并则直接将i从B中删除,并放入集合A中。
继续以上循环,直到所有剩余区间不再可以合并,即B为空集,则A为所求结果。

/**
 * Definition for an interval.
 * struct Interval {
 *     int start;
 *     int end;
 *     Interval() : start(0), end(0) {}
 *     Interval(int s, int e) : start(s), end(e) {}
 * };
 */
class Solution {
public:
    //判断两区间是否能够合并
    bool canMerge(const vector<int>&r,const vector<int>&l)
    {
        if(r[0] > l[1] || r[1] < l[0]) return false;
        
        return true;
    }
    //合并区间
    vector<int> doMerge(const vector<int> &i1, const vector<int>& i2 )
    {
        int start = min(i1[0],i2[0]);
        int end = max(i1[1],i2[1]);
        return {start,end};
    }
    
    
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        //集合A,用于存放当前合并结果。
        list<vector<int>>merged_intervals;
        //集合B,用于存放等待合并的区间
        queue<vector<int>>q;
        
        for(auto &i:intervals) q.push(i);
        
        
        while(!q.empty())
        {
           auto i = q.front();
           q.pop();
            
           if(merged_intervals.size() == 0) {
               merged_intervals.push_back(i);
           } else {
               
            bool generateNew = false;
            //将当前元素与已合并区间判断,看是否能够产生新区间
           for(auto it = merged_intervals.begin(); it!=merged_intervals.end();++it) 
           {
              //能产生新区间,则将新区间重新放入待合并队列
               if(canMerge(*it,i)){
                   auto newInterval = doMerge(*it,i);
                   merged_intervals.erase(it);
                   q.push(newInterval);
                   generateNew = true;
                   break;
               }
           } 
             //当前元素不能合并产生新区间,直接放入  
            if(generateNew == false)
            {
                merged_intervals.push_back(i);
            }
               
         }
                        
        }
        
        vector<vector<int>>result;
        for(auto &merged_intervals)
        {
            result.push_back(i);
        }
        return result;
    }
};
矩阵设0

要求尽可能少用额外空间。

颜色排序

双指针问题

class Solution {
public:
    void sortColors(vector<int>& nums) {
        if(nums.size()<=1) return ;
        auto swap=[&](int i,int j){
              int temp=nums[i];
              nums[i]=nums[j];
              nums[j]=temp;
        };
        
        //扫描向两端分拣
        int red=0;
        int blue=nums.size()-1;
        for(int i=0;i<nums.size() && red<=blue && blue>=0 &&i<=blue;){
            if(nums[i]==0){
                swap(red,i);
                ++red;
                if(i<red)i=red;
            }else if(nums[i]==2){
                swap(blue,i);
                --blue; 
            }else{
                ++i;
            }
        }
    
    }
};
数组除开自己的乘积
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值