温故而知新
回溯
机器人的运动范围
题目:
地上有一个m行和n列的方格。一个机器人从座标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行座标和列座标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
思路:
代码:
#include<vector>
class Solution {
public:
int movingCount(int threshold, int rows, int cols)
{
vector<vector<bool> > visited(rows, vector<bool>(cols));
return countHelper(threshold, rows, cols, 0, 0, visited);
}
int countHelper(const int &threshold, const int &rows, const int &cols, int rPos, int cPos, vector<vector<bool> > &visited) {
int count = 0;
if(checkPosOk(threshold, rows, cols, rPos, cPos, visited)) {
visited[rPos][cPos] = true;
count = 1
+ countHelper(threshold, rows, cols, rPos-1, cPos, visited)
+ countHelper(threshold, rows, cols, rPos, cPos-1, visited)
+ countHelper(threshold, rows, cols, rPos+1, cPos, visited)
+ countHelper(threshold, rows, cols, rPos, cPos+1, visited);
}
return count;
}
bool checkPosOk(const int &threshold, const int &rows, const int &cols, int rPos, int cPos, vector<vector<bool> > &visited) {
return rPos>=0 && rPos<rows &&
cPos>=0 && cPos<cols &&
!visited[rPos][cPos] &&
(getDigitSum(rPos) + getDigitSum(cPos) <= threshold);
}
int getDigitSum(int num) {
int next = num / 10;
int result = num % 10;
while(next!= 0) {
result += next % 10;
next = next / 10;
}
return result;
}
};
矩阵中的路径
题目:
题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串”bcced”的路径,但是矩阵中不包含”abcb”路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
关键:
1. 对回溯失败的处理
代码:
#include <cstring>
#include <vector>
using namespace std;
class Solution {
public:
bool hasPath(char* matrix, int rows, int cols, char* str)
{
vector<vector<bool> > visited(rows, vector<bool>(cols));
int pathIndex = 0;
for(int i=0;i<rows;i++) {
for(int j=0;j<cols;j++) {
if(pathHelper(matrix, rows, cols, str, i, j, pathIndex, visited))
return true;
}
}
return false;
}
bool pathHelper(char* matrix, int rows, int cols, char* str, int i, int j, int &pathIndex, vector<vector<bool> > &visited) {
if(pathIndex==(int)strlen(str))
return true;
bool pathijOk = false;
if(i>=0 && i<rows && j>=0 && j<cols && str[pathIndex]==matrix[i*cols+j] && !visited[i][j]) {
// forward
visited[i][j] = true;
pathIndex++;
pathijOk = pathHelper(matrix, rows, cols, str, i-1, j, pathIndex, visited) ||
pathHelper(matrix, rows, cols, str, i+1, j, pathIndex, visited) ||
pathHelper(matrix, rows, cols, str, i, j+1, pathIndex, visited) ||
pathHelper(matrix, rows, cols, str, i, j-1, pathIndex, visited);
if(!pathijOk) {
// if fail, then backward
pathIndex--;
visited[i][j] = false;
}
}
return pathijOk;
}
};
游走
滑动窗口的最大值
题目:
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
注意:
1. size的范围检查
2. size的类型时unsigned int, 当size = 3时,会发生类型转换,出现很诡异的1 – 3 > 0
代码:
class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size)
{
deque<int> state;
vector<int> result;
if (size > num.size() || size <= 0)
return result;
for(int i = 0; i < num.size(); i++) {
if(!state.empty() && i - (int)size >= state.front())
state.pop_front();
while(!state.empty() && num[state.back()] <= num[i])
state.pop_back();
state.push_back(i);
if(i >= (int)size - 1)
result.push_back(num[state.front()]);
}
return result;
}
};
数据流中的中位数
题目:
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
关键:
1. 维护两个堆,分别为大小堆,我们只需要两个堆的堆顶,为数据流中中间的两个数
2. 注意维护小堆的堆顶 > 大堆的堆顶
代码:
class Solution {
private:
// minheap[0] > maxheap[0]
vector<int> minheap;
vector<int> maxheap;
public:
void Insert(int num)
{
if((minheap.size()+maxheap.size()) % 2 == 0) {
// insert to minheap
if(maxheap.size()>0 && num < maxheap[0]) {
maxheap.push_back(num);
push_heap(maxheap.begin(), maxheap.end(), less<int>());
num = maxheap[0];
pop_heap(maxheap.begin(), maxheap.end(), less<int>());
maxheap.pop_back();
}
minheap.push_back(num);
push_heap(minheap.begin(), minheap.end(), greater<int>());
}
else {
// insert to maxheap
if(minheap.size()>0 && num > minheap[0]) {
minheap.push_back(num);
push_heap(minheap.begin(), minheap.end(), greater<int>());
num = minheap[0];
pop_heap(minheap.begin(), minheap.end(), greater<int>());
minheap.pop_back();
}
maxheap.push_back(num);
push_heap(maxheap.begin(), maxheap.end(), less<int>());
}
}
double GetMedian()
{
int size = minheap.size() + maxheap.size();
if (size == 0) return -1;
if (size % 2 == 1) return (double)minheap[0];
return (double)(minheap[0] + maxheap[0])/2;
}
};
二叉树
关键:
1. 想要追踪结果需要的是引用变量,所以是void Inorder(TreeNode* p, int &i, int k, TreeNode* &result)
而不是 void void Inorder(TreeNode* p, int &i, int k, TreeNode* result)
2. 同时要注意剪枝if(p == NULL || result != NULL) return;
代码:
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } }; */
class Solution {
public:
TreeNode* KthNode(TreeNode* pRoot, int k)
{
int i = 0;
TreeNode* result = NULL;
Inorder(pRoot, i, k, result);
return result;
}
void Inorder(TreeNode* p, int &i, int k, TreeNode* &result) {
if(p == NULL || result != NULL) return;
Inorder(p->left, i, k, result);
if(++i == k) result = p;
//cout<<i<<" "<<k<<" "<<result->val<<endl;
Inorder(p->right, i, k, result);
}
};
流取样
从数据流中随机取m个数
题目:
有一个很大很大的输入流,大到没有存储器可以将其存储下来,而且只输入一次,如何从这个输入流中等概率随机取得m个记录。
解答:
开辟一块容纳m个记录的内存区域,对于数据流的第n个记录,以m/n的概率将其留下(前m个先存入内存中,从第m+1个开始),随机替换m个已存在的记录中的一个,这样可以保证每个记录的最终被选取的概率都是相等的。
证明:
数学归纳法:
part1:
假设,现在流入第n+1个数据,而前面的n个数据中,每个数据在内存区域的概率为 mn m n
- 对于新流入数据,其保存在内存区域的概率为 mn+1 m n + 1
- 对于前面的n个数据,其保存在内存区域的概率为 mn+1∗(mn∗m−1m)+(1−mn+1)∗mn=mn+1 m n + 1 ∗ ( m n ∗ m − 1 m ) + ( 1 − m n + 1 ) ∗ m n = m n + 1
part2:
当n=6时
* 对于新流入数据,其保存在内存区域的概率为 56 5 6
* 对于前面的5个数据,其保存在内存区域的概率为 16+56∗(1−15)=56 1 6 + 5 6 ∗ ( 1 − 1 5 ) = 5 6
得证
二叉树
序列化二叉树
题目:
请实现两个函数,分别用来序列化和反序列化二叉树
关键:
1. substract(2)是因为只有在”#,xxxxxxxxxxx”这种情形下才继续
2. data一直在削
实现:
见链接中的Serialize and Deserialize Binary Tree