某一些没有固定做法,但就是有点trick的题
6. Z 字形变换
class Solution {
public:
string convert(string s, int numRows) {
//每一行是一个string,leetcode走到0行或者n-1行都反向
if(numRows == 1) return s;
bool down = false;
vector<string> rows(numRows);
int cur = 0;
for(auto c : s)
{
rows[cur] += c;
if(cur == 0 || cur == numRows - 1) down = !down;
if(down) cur ++;
else cur --;
}
string res;
for(auto x : rows) res += x;
return res;
}
};
121. 买卖股票的最佳时机(剑指 Offer 63. 股票的最大利润)
j记录最低点的价值即可,每次用当前的值-min,得到的肯定是当前买入的收益最大值
class Solution {
public:
int maxProfit(vector<int>& prices) {
int min = INT_MAX,n = prices.size();
int res = 0;
for(int i = 0; i < n; i ++)
{
if(prices[i] < min) min = prices[i];//每次更新的时候,记录最低点,并且计算假如当前是在最低点买入的
res = max(res, prices[i] - min);
}
return res;
}
};
128. 最长连续序列
都存到map里,遍历的时候如果是没有被遍历过(map中没有x-1,也就是x带来了新的序列),就一直往后遍历
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_map<int, int> map;
for(int n : nums) map[n] ++;
int res = 0;
for(int x : nums)//看似两重循环,其实只会被查找一次,因为只有它带来了新序列才会遍历后面的,否则不管它
{
if(!map.count(x - 1))//不包含前一个,说明是出现的新序列,往后一直找
{
int curnum = x;
int curcnt = 1;
while(map.count(curnum + 1))//往后一直遍历
{
curnum += 1;
curcnt += 1;
}
res = max(res, curcnt);
}
}
return res;
}
};
169. 多数元素(剑指 Offer 39. 数组中出现次数超过一半的数字)
class Solution {
public:
int majorityElement(vector<int>& nums) {
//方法二:投票,众数看作1,其他数看作-1,遇到一个众数会抵消一个非众数
int cnt = 0, candidate;
for(int i = 0; i < nums.size(); i ++)
{
if(cnt == 0) candidate = nums[i];
if(candidate == nums[i]) cnt ++;
else cnt --;
}
return candidate;
}
};
剑指 Offer 03. 数组中重复的数字
交换到指定位置:0,n-1
class Solution {
public:
int findRepeatNumber(vector<int>& nums)
{
for(int i = 0; i < nums.size();)
{
if(i != nums[i])
{
int t = nums[i];
if(t == nums[t]) return t;
else swap(nums[i], nums[t]);
}
else i ++;
}
return -1;
}
};
剑指 Offer 61. 扑克牌中的顺子
class Solution {
public:
bool isStraight(vector<int>& nums) {
if(nums.empty()) return false;
sort(nums.begin(), nums.end());//先排序
int k = 0;
while(!nums[k]) k ++;//把行首的0去掉
for(int i = k + 1;i < nums.size(); i ++)
{
if(nums[i] == nums[i-1]) return false;//有相同元素
}
return nums.back() - nums[k] <= 4;//最大数-非0最小数,因为已经有5个不重复的值
//肯定不可能超过4
//[1,4]再补充一个[0]==5就好
//[1,3]再补充[0]==4,5就好
//[1,2]不可能,因为最少就有3个数,差值肯定>=2
}
};
55. 跳跃游戏
class Solution {
public:
bool canJump(vector<int>& nums) {
//更新可以到达的最远位置:意思是这个最远位置前的位置都可以到达
int n = nums.size();
int max_len = 0;
for(int i = 0; i < n; i ++)//o(n)
{
if(i <= max_len) //i>r的话i位置都到达不了
{
max_len = max(max_len, i + nums[i]);//更新最远距离
if(max_len >= n-1) return true;
}
}
return false;
}
};
剑指 Offer 45. 把数组排成最小的数
为什么从小到大的顺序就对呢?假设最终答案的最小值是存在逆序的,a>b但是a在b前面:若abXXX XXabXX肯定不对,因为a>b,若aXXXb,设为ayb,则因为这个数是最小的,所以ay<ya,yb<by=>a<y<b,与已知a>b矛盾,所以不存在逆序的
class Solution {
public:
static bool cmp(int a , int b)
{
auto as = to_string(a), bs = to_string(b);
return as + bs < bs + as;//字符串拼到一起
}
string minNumber(vector<int>& nums) {
sort(nums.begin(), nums.end(),cmp);//自定义的排序
string res;
for(auto x : nums) res += to_string(x);
return res;
}
};
剑指 Offer 29. 顺时针打印矩阵
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> res;
int n = matrix.size();
if(!n) return res;
int m = matrix[0].size();
vector<vector<int>> map(n, vector<int> (m, 0));//map记录
int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};//4个方向
int s = m * n;
int t = 0;
int x = 0, y = 0;
for(int i = 0; i < s; i ++)
{
if(!map[x][y]) {res.push_back(matrix[x][y]); map[x][y] = 1;}
int a = x, b = y;
x += dx[t], y += dy[t];
if(x < 0 || x >= n || y < 0 || y >= m || map[x][y])//遇到转移方向的时候
{
t = (t + 1) % 4;
x = a + dx[t], y = b + dy[t];
}
}
return res;
}
};
剑指 Offer 64. 求1+2+…+n
class Solution {
public:
int sumNums(int n) {
int res = n;
n > 0 && (res += sumNums(n-1)); //if(n>0) res += sumNums(n-1);因为&&和||都是先执行前面,前面不满足不会执行后面
return res;
}
};
48. 旋转图像
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
if (matrix.empty() || matrix[0].empty()) return;
int n = matrix.size();
//先沿正对角线对调
for (int i = 0; i < n; i ++){
for (int j = i; j < n; j ++){
swap(matrix[i][j], matrix[j][i]);
}
}
//再按照竖轴对调
for (int i = 0; i < n; i ++){
int l = 0, r = n - 1;
while (l < r) swap(matrix[i][l ++], matrix[i][r --]);
}
}
};
剑指 Offer 62. 圆圈中最后剩下的数字
class Solution {
public:
int lastRemaining(int n, int m) {
//约瑟夫环问题
if(n == 1) return 0;
return (lastRemaining(n - 1, m) + m) % n;
}
};
31. 下一个排列
class Solution {
public:
void nextPermutation(vector<int>& nums) {
//3步:
//1.要让变大后的数尽可能小:从右开始找到第一个逆序的数(在有限的排列中,降序是最大值,升序是最小值,所以降序部分是无法改变的,找到第一个升序的地方进行改变)
//2.a[i]>a[i-1]时,i-1就是要找的位置,把它与右侧开始找的第一个大于它的数a[j]交换,5,6,11,9,7,5,3,1中找到6后与7交换,
//3.交换后的值11往后肯定是降序的,是最大的,翻转得到最小的
if(nums.size() == 1 || nums.empty()) return ;//特殊情况
int n = nums.size();
int i = n - 1;//注意弄成全局变量
for(; i >= 1; i --) if(nums[i] > nums[i - 1]) break;//第一步找到升序的
if(i == 0) reverse(nums.begin(),nums.end());//如果没有升序说明是最大值,直接返回
else{
int tmp = nums[i - 1];//第二步找到比i-1大一点的数
int j = n - 1;
for(; j >= 0; j --) if(nums[j] > tmp) break;
swap(nums[i - 1], nums[j]);
reverse(nums.begin() + i,nums.end());//第三步翻转
return ;
}
}
};