1. Shuffle an Array
打乱一个没有重复元素的数组。
解题思路:如果你从前向后遍历,遍历一次,然后选择目标位置和当前位置对换,看似足够随机,实则是错误的做法。这是为什么呢?
证明
:这里并不需要多么深奥的数学知识,只需要高中所学的概率论的基础知识。当年有这样一道题:有n个球,随机放到n个格子,那么一共有多少种方法。题中抽象出来,不就是这个问题吗?应该怎么做?首先,从一堆球中随机选出一个放到1格中,然后从剩下的n-1个格子中选出一个放到2格中,依次类推,一共有n!种情况,这个是正确答案。
那么,当你在遍历到第i个格子时,依旧用rand()%nums.size()进行选择,那么你的程序可能获得的种类就是n^n中情况,多计算了n^n-n!情况,这根本就不是随机相同概率。
那么我们应该怎么?我们把这个数组单层空的格子,首先,我们要获取到第一个格子应该放的元素,从n个数中随机找一个,即数组下标为rand()%nums.size(),然后放到第一个格子中,第二个格子,我们就需要从n-1个数中随机找一个,即数组下标为1+rand()%(nums.size()-1),放到第二个格子中。
依次类推,
第i个格子应该放的元素是数组下标为i+rand()%(nums.size() -i)的数。
bingo,公式推导完毕。
public:
Solution(vector<int> nums): v(nums) {}
/** Resets the array to its original configuration and return it. */
vector<int> reset() {
return v;
}
/** Returns a random shuffling of the array. */
vector<int> shuffle() {
if(0 >= v.size())//注意数组为空的情况。
return v;
vector<int> res(v);
for (int i = 0; i < res.size()-1; ++i) {
int select = i + rand() % (res.size()-i);
swap(res[i], res[select]);
}
return res;
}
private:
vector<int> v;
2. 最小栈
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) -- 将元素 x 推入栈中。
pop() -- 删除栈顶的元素。
top() -- 获取栈顶元素。
getMin() -- 检索栈中的最小元素。
解题思路:需要参数时间内找到最小元素的栈,一个额外栈记录最小数,主栈中的最小数被pop,相应的记录栈中依然被pop,这时记录栈的栈顶的最小数依然是被pop的那个最小数出现之前的最小数。栈的最大功能就是记忆~
public:
/** initialize your data structure here. */
MinStack() {
}
void push(int x) {
main.push(x);
if(0 == min.size())
{
min.push(x);
return ;
}
if(x<=min.top())
min.push(x);
}
void pop() {
if( main.top() == min.top())
min.pop();
main.pop();
}
int top() {
return main.top();
}
int getMin() {
return min.top();
}
private:
stack<int> main;
stack<int> min;
网友评论