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 依次检查每个数字,让其物归原处
迭代\位置 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 解析 |
---|---|---|---|---|---|---|---|---|---|
<1> | -3 | 7 | 8 | 1 | 2 | 9 | 11 | 12 | -3不是正数,跳过 |
<2> | -3 | 7 | 8 | 1 | 2 | 9 | 11 | 12 | 7不在自己位置上,第7个位置上是11 |
<3> | -3 | 11 | 8 | 1 | 2 | 9 | 7 | 12 | 把7放到第7个位置,11被调换回来继续从当前位置检查。11超过最大位置,跳过 |
<4> | -3 | 11 | 8 | 1 | 2 | 9 | 7 | 12 | 8不在自己位置,同样物归原处 |
<5> | -3 | 11 | 12 | 1 | 2 | 9 | 7 | 8 | 检查12,12超过最大位置,跳过 |
<6> | -3 | 11 | 12 | 1 | 2 | 9 | 7 | 8 | 1不在自己位置,物归原处 |
<7> | 1 | 11 | 12 | -3 | 2 | 9 | 7 | 8 | -3不是正数,跳过 |
<8> | 1 | 11 | 12 | -3 | 2 | 9 | 7 | 8 | 2不在自己位置,物归原处 |
<9> | 1 | 2 | 12 | -3 | 11 | 9 | 7 | 8 | 11超过最大位置,跳过 |
<10> | 1 | 2 | 12 | -3 | 11 | 9 | 7 | 8 | 9超过最大位置,跳过 |
<11> | 1 | 2 | 12 | -3 | 11 | 9 | 7 | 8 | 剩下数字都在自己位置上,结束物归原处阶段 |
阶段2 得到第一个不是物归原处的位置
迭代\位置 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 解析 |
---|---|---|---|---|---|---|---|---|---|
检查 | 1 | 2 | 12 | -3 | 11 | 9 | 7 | 8 | 第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;
}
}
}
};