很无聊的一道题,无非是考一个提前量而已
/*
* 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;
* Iterator(const vector& 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 {
int nCurr;
bool bEnd;
public:
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.
bEnd = false;
if (Iterator::hasNext())
{
nCurr = Iterator::next();
}
else
{
bEnd = true;
}
}
// Returns the next element in the iteration without advancing the iterator.
int peek()
{
return nCurr;
}
// hasNext() and next() should behave the same as in the Iterator interface.
// Override them if needed.
int next()
{
if (bEnd)
{
return -1;
}
int res = nCurr;
if (Iterator::hasNext())
{
nCurr = Iterator::next();
}
else
{
bEnd = true;
}
return res;
}
bool hasNext() const
{
return !bEnd;
}
};
本题可以通过二分查找或者二进制位操作进行,但是最佳做法是类似于142题的快慢指针求解。这里有三个关键点:1. 我们以数组值作为下一个索引项,以此构建了一个图。由于有重复值,所以该图一定有环路 2. 因为索引从0开始而数值从1开始,因此快慢指针不可能在开始循环的时候陷入原地死循环。 3. 找到数之后再次循环,相遇的位置即为环的接入点,即重复元素值
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int slow = 0, fast = 0;
do {
slow = nums[slow];
fast = nums[nums[fast]];
} while (slow != fast);
slow = 0;
while (slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
};
本题有一个陷阱就是已修改的可能对未修改的产生影响,不适用额外空间的话比较好的办法是使用额外的标记,如0表示死亡,1表示活着,增加2表示从死亡活过来,-1表示从活变成死亡即可完美解决
class Solution {
public:
void gameOfLife(vector<vector<int>>& board) {
int neighbors[3] = {0, 1, -1};
int rows = board.size();
int cols = board[0].size();
// 遍历面板每一个格子里的细胞
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
// 对于每一个细胞统计其八个相邻位置里的活细胞数量
int liveNeighbors = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (!(neighbors[i] == 0 && neighbors[j] == 0)) {
// 相邻位置的坐标
int r = (row + neighbors[i]);
int c = (col + neighbors[j]);
// 查看相邻的细胞是否是活细胞
if ((r < rows && r >= 0) && (c < cols && c >= 0) && (abs(board[r][c]) == 1)) {
liveNeighbors += 1;
}
}
}
}
// 规则 1 或规则 3
if ((board[row][col] == 1) && (liveNeighbors < 2 || liveNeighbors > 3)) {
// -1 代表这个细胞过去是活的现在死了
board[row][col] = -1;
}
// 规则 4
if (board[row][col] == 0 && liveNeighbors == 3) {
// 2 代表这个细胞过去是死的现在活了
board[row][col] = 2;
}
}
}
// 遍历 board 得到一次更新后的状态
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
if (board[row][col] > 0) {
board[row][col] = 1;
} else {
board[row][col] = 0;
}
}
}
}
};
1.定义两个map,为何定义两个呢? 防止[aaaa]与[cat dog dog cat]、[abba]与[cat cat cat cat]时输出true
2.用stringstream可以自动输出词组
3.判断:!(ss >> s)判断pattern长度是否大于str长度,且将ss容器中字符串赋值给s
4.判断:(map.count© == 1 && map[c] != s) || (rmap.count(s) == 1 && rmap[s] != c)) 来判断是否匹配
5.判断:(ss >> s) ? false : true 判断str长度是否大于pattern长度
class Solution {
public:
bool wordPattern(string pattern, string str)
{
unordered_map<char, string> map;
unordered_map<string, char> rmap;
stringstream ss(str); string s;
for(char c : pattern)
{
if(!(ss >> s) || (map.count(c) == 1 && map[c] != s)
|| (rmap.count(s) == 1 && rmap[s] != c))
return false;
map[c] = s;
rmap[s] = c;
}
return (ss >> s) ? false : true;
}
};
当i个必败的情况下,i + 1, i + 2, i + 3必胜,因此i 为4的倍数则必败,否则必胜
class Solution {
public:
bool canWinNim(int n) {
if (n <= 3)
return true;
return !(n % 4 == 0);
}
};
最简单的做法就是用动态数组保存,然后每次查询的时候先排序再取中间数。优化版的方法是每次保存均插入在排序的位置上,即查询的时候不需要排序。更好的方法是采取两个堆:一个最小堆一个最大堆,由此两个堆的堆顶即是中位数。该做法需要做到两个堆的平衡,但是总体复杂度较容器低。除此之外还可以采取自平衡树,也有类似的效果。
class MedianFinder {
priority_queue<int> lo; // max heap
priority_queue<int, vector<int>, greater<int>> hi; // min heap
public:
// Adds a number into the data structure.
void addNum(int num)
{
lo.push(num); // Add to max heap
hi.push(lo.top()); // balancing step
lo.pop();
if (lo.size() < hi.size()) { // maintain size property
lo.push(hi.top());
hi.pop();
}
}
// Returns the median of current data stream
double findMedian()
{
return lo.size() > hi.size() ? (double) lo.top() : (lo.top() + hi.top()) * 0.5;
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/
class MedianFinder {
multiset<int> data;
multiset<int>::iterator mid;
public:
MedianFinder()
: mid(data.end())
{
}
void addNum(int num)
{
const int n = data.size();
data.insert(num);
if (!n) // first element inserted
mid = data.begin();
else if (num < *mid) // median is decreased
mid = (n & 1 ? mid : prev(mid));
else // median is increased
mid = (n & 1 ? next(mid) : mid);
}
double findMedian()
{
const int n = data.size();
return (*mid + *next(mid, n % 2 - 1)) * 0.5;
}
};
采用递归或者堆栈均可,说白了就是二叉树的前中后序遍历加一个字符串处理而已,没有难度
/**
* 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:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
string res;
dfs_s(root, res);
return res;
}
// 前序遍历序列转化为字符串
void dfs_s(TreeNode* root, string& res) {
if (!root) {
res += "null ";
return;
}
res += to_string(root->val) + ' ';
dfs_s(root->left, res);
dfs_s(root->right, res);
}
// 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 (u >= data.size()) return NULL;
if (data[u] == 'n') {
u = u + 5;
return NULL;
}
int val = 0, sign = 1;
if (data[u] == '-') sign = -1, u ++ ;
while(data[u] != ' '){val = val * 10 + data[u] - '0'; u++;}
val *= sign;
u = u + 1 ;
auto root = new TreeNode(val);
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 codec;
// codec.deserialize(codec.serialize(root));