1.数组
1.1 知识点
- List item
- 动态数组vector的使用
- 双指针技巧
1)首尾双指针用于排序等任务,处理效率更高
2)快慢双指针用于空间受限制时:一个用于迭代,而第二个指针总是指向下一次添加的位置。
1.2 题目类型总结
- 查找索引,如两数之和
- 寻找特殊数字
- 反转
- 排序
- 二维数组之花式引用与更改顺序输出
1.2 二维数组1:对角线遍历
好难好难,一脸懵逼.
以对角线入手进行观察:
- 奇数行对角线是往上的,在不遇到上边界时行列的变化为(-1,1),遇到上边界时,变化为(0,1);在遇到矩阵角点时,变化为(1,0)
- 偶数行对角线是往下的,不遇到左边界时行列的变化为(1,-1),遇到左边界时,变化为(1,0),遇到下边界时,变化为(0,1)
遇到任何边界时将切换到下一条对角线,k值转换;并处理边界即可
vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
if (matrix.empty() || matrix[0].empty()) return {};
// 矩阵行列;k用于控制对角线行数的的奇偶
int m = matrix.size(), n = matrix[0].size(), r = 0, c = 0, k = 0;
vector<int> res(m * n);//结果
vector<vector<int>> dirs{{-1,1}, {1,-1}};
for (int i = 0; i < m * n; ++i) {
res[i] = matrix[r][c];
r += dirs[k][0];
c += dirs[k][1];
if (r >= m) {r = m - 1; c += 2; k = 1 - k;}//遇到下边界
if (c >= n) {c = n - 1; r += 2; k = 1 - k;}//遇到右边界
if (r < 0) {r = 0; k = 1 - k;} //遇到上边界
if (c < 0) {c = 0; k = 1 - k;}//上到左边界
}
return res;
}
1.3 二维数组2:螺旋数组
想想一下你在开车,碰到指示牌就转向…你遇到指示牌后必须调整该指示牌的下一个位置。
还需注意:当列数大于行数的时候,可能会遇到错误的转向,比如3*5的矩阵,在1,1位置会错误转上。
因而采用pair数组来记录当前的方向,只有当当前方向和路标条件吻合顺时针走法时才做出相应调整。
over!
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> result;
if(matrix.size()<1) return result;
int m = matrix.size();//行数
int n = matrix[0].size();//列数
// 四块指示牌
pair<int,int> right(1,0);
pair<int,int> down(0,n-1);
pair<int,int> left(m-1,n-1);
pair<int,int> up(m-1,0);
pair<int,int> velocity(0,1);//速度
enum flag{_Left,_Right,_Up,_Down};
pair<int,int> coor(0,0);//当前坐标
flag last_flag(_Right);//当前状态
for(int i=0;i<m*n;i++){
int ele = matrix[coor.first][coor.second];
result.push_back(ele);
// 遇到拐点响应的改变速度,否则不变
if(coor==down && last_flag==_Right){
velocity= make_pair(1,0);
down.first = coor.first+1;
down.second = coor.second-1;
last_flag = _Down;
}else if(coor==left && last_flag==_Down){
velocity= make_pair(0,-1);
left.first = coor.first-1;
left.second = coor.second-1;
last_flag = _Left;
}else if(coor==up && last_flag==_Left){
velocity= make_pair(-1,0);
up.first = coor.first-1;
up.second = coor.second+1;
last_flag = _Up;
}else if( coor==right && last_flag==_Up){
velocity= make_pair(0,1);
right.first = coor.first+1;
right.second = coor.second+1;
last_flag= _Right;
}
coor.first += velocity.first;
coor.second += velocity.second;
}
return result;
}
};
1.4 二维数组3:杨辉三角1
写到这里感觉自己的做题方式有问题,经常陷入个人思考,而现在段位还比较低…所以感觉挺浪费时间的,毕竟不久也容易忘记。不如先参考别人的思路,然后自己写代码。以后再温习温习。
言归正传,这题就找规律,第i行具有i个数,并且每一行都是对称的,因而可以利用双指针进行优化。
res[i][j]=res[i-1][j-1]+res[i-1][j];注意i和j的定义和数组边界即可。
vector<vector<int>> generate(int numRows) {
vector<vector<int> > result;
// 第i行具有i个数
for(int i=0;i<numRows;i++){
vector<int> rowTemp(i+1,1);
if(i>1){
for(int p=1,q=i-1;p<=q;p++,q--){
rowTemp[p] = result[i-1][p-1]+result[i-1][p];//上一行的对应下标的数和下标减一的数之和
rowTemp[q] = result[i-1][p-1]+result[i-1][p];//两边对称
}
}
result.push_back(rowTemp);
}
return result;
}
2.字符串
2.1 知识点
- 字符串string
学问很多,比如子串、比较还有和数字字符串的处理,有时间得专门总结一下数字和字符的转换。
字符串与数字的转换
参考链接:字符串与数字的转换
// 字符串与数字的转换
// Created by wbzhang on 2020/3/12.
// 摘自博客:https://blog.csdn.net/u011251945/article/details/81609821?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <sec_api/string_s.h>
using namespace std;
int main(){
1- 数字转字符串
int num =12;
char numS[10];
// 1.1 通过内存拷贝的方式将int转化为字符串
sprintf_s(numS,"%d",num);
cout<<"numS:"<< numS <<endl;
// 1.2 字符串的字符流转换
int n0 = 101;
string str1;
stringstream ss;
ss << n0;
ss >> str1;
cout<<"str1:"<< str1 <<endl;
// 或者 用ostringstream
string str0;
ostringstream os;
os << n0;
str0 = os.str();
cout<<"str0:"<< str0 <<endl;
//1.3 c_str
string str2 = "123";
char *dest = new char [10];
strcpy_s(dest, 5, str2.c_str());
// cout<"dest:" << (*dest) <<endl;
2-字符串转数字
string str3 = "101";
//c++11中字符串转int
int m = stoi(str3); // string to int
//各种数字类型转字符串int,float,long,double等
string str4 = to_string(m); //数字转字符串
3- 将字符串转为各种进制格式,取决于string的表达方式
cout << "16进制: " << stoi(str3, nullptr,16) <<" "<<"2进制:"<<stoi(str3, nullptr, 2) << endl;
cout << "10进制:" << stoi(str3, nullptr, 10) << " " << "8进制:" << stoi(str3, nullptr, 8) << endl;
4- c语言中的字符串转数字
// 我记得应该还有wtoi这些,w表示宽字符,学问挺多的
//c语言中字符串转float
float n = atof(str3.c_str()); // ascii to float
//c库中字符串转long
long n1 = atol(str3.c_str()); // ascii to long
//c库中字符串转int
int n2 = atoi(str3.c_str());
5-字母大小写转换与ascii
string str5 = "nihao";
//小写字母转大写字母
for (int i = 0; i < str5.size(); i++)
str5[i] = toupper(str5[i]);
//小写字母转大写字母
for (int i = 0; i < str5.size(); i++)
str5[i] = tolower(str5[i]);
//数字转ASCII
int n3 = 65;
char c = toascii(n3);
system("pause");
return 0;
}
还有通过ascii进行字符和整数之间的转换
// 单个字符转数字
char s='9';
int numS = int(s-'0'); // 0的ASCII码是48
//单个数字转字符
int num = 9;
char numStr = num+'0';
常见ASCII码
- 0-NUL 空字符
- 13-CR 回车键
- 32-space 空格键
- 48- 字符0
- 57-字符9
- 65-大写字母A
- 90-大写字母Z
- 97-小写字母a
- 122-小写字母z
- 127-删除
2.2 最长公共子串
很简单的题,但是我的做法太繁琐了,主要我没用substr。还是来学习一下大神的解答~
解法1:这个第一行好评!这种写法舒适啊。substr(ind,length)作切片当索引加长度超出数组长度时,会返回索引到数组最后一个元素,而不必担心越界。没啥可说的了…
string longestCommonPrefix(vector<string>& strs) {
string r = strs.size() ? strs[0] : "";
for(auto s: strs){
while(s.substr(0, r.size()) != r){
r = r.substr(0, r.size() - 1);
if(r == "") return r;
}
}
return r;
}
解法2:第j(j>1)个字符串的第i个字符与第一个字符串的的第i个字符不同时,返回此时对第一个字符串的切片。
string longestCommonPrefix(vector<string>& strs) {
if(strs.size()==0) return "";
for(int i=0;i<strs[0].size();i++)
for(int j=1;j<strs.size();j++)
if(strs[j][i]!=strs[0][i])
return strs[0].substr(0,i);
//substr取前i个元素,因为索引i对应的是第i+1个元素不是共有的,所以前i个是共有前缀
return strs[0];
}
2.3 长度最小的数组
题解:
1)双指针法:取首尾指针p和q,如果p与q之间的总和<s;返回0
否则,比较p和q的大小,若*p>=*q,则q–;否则p++;
直到p==q或者两者之间的和<s时,返回q-p