283. 移动零
分析
双指针算法
如果x不是0, 就放到当前位置上, 当前位置++
扫描一遍完后, 将后面的所有数字置0
code
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int k = 0;
for (auto& x : nums)
if (x) nums[k ++ ] = x;
while (k < nums.size()) nums[k ++ ] = 0;
}
};
284. 顶端迭代器
分析
增加一个额外的缓存, 来放置当前的数
如果是peek
操作, 就将缓存中的元素输出
next
将缓存的元素输出, 同时将后面的元素移到缓存上
hasNext
code
/*
* Below is the interface for Iterator, which is already defined for you.
* **DO NOT** modify the interface for Iterator.
*
* class Iterator {
* struct Data;
* Data* data;
* public:
* Iterator(const vector<int>& nums);
* Iterator(const Iterator& iter);
*
* // Returns the next element in the iteration.
* int next();
*
* // Returns true if the iteration has more elements.
* bool hasNext() const;
* };
*/
class PeekingIterator : public Iterator {
public:
int cur;
bool has_next;
PeekingIterator(const vector<int>& nums) : Iterator(nums) {
// Initialize any member here.
// **DO NOT** save a copy of nums and manipulate it directly.
// You should only use the Iterator interface methods.
has_next = Iterator::hasNext();
if (has_next) cur = Iterator::next();
}
// Returns the next element in the iteration without advancing the iterator.
int peek() {
return cur;
}
// hasNext() and next() should behave the same as in the Iterator interface.
// Override them if needed.
int next() {
int t = cur;
// 将下一个元素放到展台上
has_next = Iterator::hasNext();
if (has_next) cur = Iterator::next();
return t;
}
bool hasNext() const {
return has_next;
}
};
287. 寻找重复数
分析
转化成找环的入口的问题
0的位置上是1
0->1
1的位置上是3
1->3
2的位置上是4
2->4
3的位置上是2
3->2
4的位置上是2
4->2
联动
leetcode 142 环的入口
code
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int a = 0, b = 0;
while (true) {
a = nums[a];
b = nums[nums[b]];
if (a == b) {
a = 0;
while (a != b) {
a = nums[a];
b = nums[b];
}
return a;
}
}
return -1;
}
};
289. 生命游戏
分析
模拟题
code
class Solution {
public:
void gameOfLife(vector<vector<int>>& board) {
if (board.empty() || board[0].empty()) return ;
int n = board.size(), m = board[0].size();
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ ){
int live = 0;
for (int x = max(0, i - 1); x <= min(n - 1, i + 1); x ++ )
for (int y = max(0, j - 1); y <= min(m - 1, j + 1); y ++ )
if ((x != i || y != j) && (board[x][y] & 1)) // 不包括自己x != i || y != j
live ++;
int cur = board[i][j] & 1, next;
if (cur == 1) {
if (live < 2 || live > 3) next = 0;
else next = 1;
}else {
if (live == 3) next = 1;
else next = 0;
}
board[i][j] |= next << 1;
}
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
board[i][j] >>= 1;
}
};
290. 单词规律
分析
判断映射, 和单射就可以了
code
class Solution {
public:
bool wordPattern(string pattern, string str) {
vector<string> words;
stringstream ssin(str);
string word;
while (ssin >> word) words.push_back(word);
if (pattern.size() != words.size()) return false;
unordered_map<char, string> pw;
unordered_map<string, char> wp;
for (int i = 0; i < pattern.size(); i ++ ) {
auto a = pattern[i];
auto b = words[i];
if (pw.count(a) && pw[a] != b) return false;
pw[a] = b;
if (wp.count(b) && wp[b] != a) return false;
wp[b] = a;
}
return true;
}
};
292. Nim 游戏
分析
当前是0颗石子的话, 必输
当前是1颗石子的话, 那我们只需要拿1颗石子, 那么对手必输, 我们必胜
1, 2, 3 全拿走就可以了
4的话, 拿1颗石子, 变成3, 3的话对手必胜, 我们必输
拿2颗石子, 也是输, 拿1颗石子也是输
因此4颗石子的话, 我们先手, 无论怎么拿也是输
如果是5的话, 我们拿1颗石子, 对手就会进入4, 那么对手必输
同样的道理, 6, 7都是必胜, 因为可以转化到4, 令对手必输
8的话必输
找下规律, 可以发现 n % 4 == 0的话, 必输
n % 4 != 0的话, 必胜
如果n % 4 != 0的话, 第1次拿 n % 4就可以了, 拿完石子个数就变成n % 4 == 0, 是4的倍数, 然后不管对手拿多少(设对手拿了x), 我们都拿 4 - x
如果上来就是 n % 4 == 0的话, 不管我们拿多少, 对手可以拿 4 - x, 所以我们必输
code
class Solution {
public:
bool canWinNim(int n) {
return n % 4;
}
};
295. 数据流的中位数
分析
维护一个对顶堆, 保证下面比上面的数多1个
如果整个数列个数是奇数, 返回下面的堆顶
如果是偶数, 那么返回两个堆顶的平均值
插入:
如果 t <= x, 那么将t放到下面
否则; 表示t在右半边, 将t放到上面
插完之后, 上下元素个数不满足要求了; 比如下面比上面元素多2个, 那么需要将下面这个堆的堆顶放到上面
同理上面的多的话, 需要将上面的堆顶移动到下面堆
所以插入操作只需要常数次的操作O(logn)
查询操作是O(1)的
code
class MedianFinder {
public:
priority_queue<int, vector<int>, greater<int>> up;
priority_queue<int> down;
/** initialize your data structure here. */
MedianFinder() {
}
void addNum(int num) {
if (down.empty() || down.top() >= num) {
down.push(num);
if (down.size() > up.size() + 1) {
up.push(down.top()); down.pop();
}
}else {
up.push(num);
if (up.size() > down.size()){
down.push(up.top()); up.pop();
}
}
}
double findMedian() {
if ((down.size() + up.size()) % 2) return down.top();
else return (down.top() + up.top()) / 2.0;
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/
297. 二叉树的序列化与反序列化
分析
基于dfs的先序遍历
code
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Codec {
public:
string path;
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
dfs_s(root);
return path;
}
void dfs_s(TreeNode* root){
if (!root) path += "#,";
else {
path += to_string(root->val) + ',';
dfs_s(root->left);
dfs_s(root->right);
}
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
int u = 0;
return dfs_d(data, u);
}
TreeNode* dfs_d(string& data, int& u) {
if (data[u] == '#') {
u += 2; // 当前是空, 需要跳过两个字符, 一个#, 一个,
return NULL;
}else {
int k = u;
while (data[u] != ',') u ++ ;
auto root = new TreeNode(stoi(data.substr(k, u - k)));
u ++ ; // 跳过逗号
root->left = dfs_d(data, u);
root->right = dfs_d(data, u);
return root;
}
}
};
// Your Codec object will be instantiated and called as such:
// Codec ser, deser;
// TreeNode* ans = deser.deserialize(ser.serialize(root));
299. 猜数字游戏
分析
hash表存一下次数就可以了
tot
表示总的在两个字符串出现过的次数
buills
表示对应位置 相同的次数
code
class Solution {
public:
string getHint(string secret, string guess) {
unordered_map<char, int> hash;
for (auto c : secret) hash[c] ++ ;
int tot = 0;
for (auto c : guess)
if (hash[c] > 0) {
tot ++ ;
hash[c] -- ;
}
int bulls = 0;
for (int i = 0; i < secret.size(); i ++ )
if (secret[i] == guess[i])
bulls ++ ;
return to_string(bulls) + "A" + to_string(tot - bulls) + "B";
}
};
300. 最长递增子序列
分析(nlogn)
求一下以每个数结尾的最长上升子序列
找到最大的一个长度, 使得在这个长度下, 结尾的最大值<a[i]
最大的长度+1, 就是以a[i]
结尾的最大长度
code
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> q;
for (auto x : nums) {
if (q.empty() || x > q.back()) q.push_back(x);
else {
if (x <= q[0]) q[0] = x;
else {
int l = 0, r = q.size() - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (q[mid] < x) l = mid;
else r = mid - 1;
}
q[r + 1] = x;
}
}
}
return q.size();
}
};