名人问题
问题:
在一个房间里有 N 个人,其中一个是名人,所谓名人就是大家都认识他,但是他不认识任何人。其它人可能认识房间里面另外的一部分人。你可以问任何人问题,但是问题只能是:你认识 X 吗,对方回答 Yes or No. 请问最少要问多少个问题才能把名人找出来?
分析:
我们把人编号,比如从1 到 N。
我们考虑最坏情况:你问每一个人是否认识 X ,如果大家都认识,那么 X 一定是名人,如果其中一个人说不认识,那么那个人一定不是名人。因为 X 的范围是 1 到 N, 所以,在最坏情况下,我们 要问 (N - 1)* N 个问题。
但是,有一种更好的方法。我们从1开始,依次问他是否认识他的下一个,比如 2, 如果 1 说认识,那么 1 一定不是名人,2 有可能是名人; 如果1 说不认识,2 一定不是名人,1 却有可能是名人。这是这个方法巧的地方。所以,不管1 回答是还是不是,我们都可以确定其中一个不是名人,然后,我们继续问 可能是名人那一位 是否认识 3, 然后依次下去,直到第 N 个人。这样我们就可以只要问 (N - 1) 个问题就可以把名人找出来。
原文链接:https://blog.youkuaiyun.com/beiyeqingteng/article/details/7707485
积水问题
解题思路:当前位置能蓄水要求两边的高度都高于当前位置,所以我们扫描到当前位置,只需判断当前位置是否对蓄的水有贡献。
当前位置宽度为1最终的贡献值,为左边高度的最大值和右边高度的最大值,取其中最小的,然后和当前高度相减,如果大于0,则这个值就是贡献值
class Solution {
public:
int trap(vector<int>& height) {
int water = 0;
int size = height.size();
for (int i = 1; i < size - 1; i++) {
int max_left = 0, max_right = 0;
for (int j = i; j >= 0; j--) { //Search the left part for max bar size
max_left = max(max_left, height[j]); //左边最大值
}
for (int j = i; j < size; j++) { //Search the right part for max bar size
max_right = max(max_right, height[j]); //右边最大值
}
water += min(max_left, max_right) - height[i]; //和这个本身进行比较,且不会出现负值
}
return water;
}
};
装最多的水
分别在头、尾元素定义两个指针 l , r ;
如图所示,遍历数组,直到两个指针相遇,停止循环
/// Two Pointers
/// Time Complexity: O(n)
/// Space Complexity: O(1)
class Solution {
public:
int maxArea(vector<int>& height) {
assert(height.size() >= 2);
int l = 0, r = height.size() - 1;
int area = 0;
while(l < r){
area = max(area , min(height[l], height[r]) * (r - l));//不断更新,高乘宽
if(height[l] < height[r]) //移动小的那个
l ++;
else
r --;
}
return area;
}
};
证明是对的:一定扫过最优解
最大间隔问题(不太懂)
问题描述:给定n个乱序的实数,求这些数在实数轴上相邻2个数之间的最大差值,假设对任何实数的下取整函数耗时O(1),设计解最大间隙问题的线性时间算法。
思路:如果采用先排序,再求解最大间隙的方式,即使是采用堆排序,解处该问题的复杂度也在O(nlogn)。要在线性时间内求解,可以采用“鸽舍原理”,我们首先找到这组数的最大和最小值,将两个数之间的数轴分为n+1份,将这n个数依次放到这n+1个区间中,由“鸽舍原理”可知,其中必有一个区间没有数,则最大间距应是该区间的前一个区间中最大数与该区间后一个区间中最小数之间的差值。
float max_num(float num_arr[], int n) { #找出该组数中最大值。
float temp = num_arr[0];
for (int i = 1;i < n;i++) {
if (temp < num_arr[i]) temp = num_arr[i];
}
return temp;
}
float min_num(float num_arr[], int n) {#找出该组数中最小值。
float temp = num_arr[0];
for (int i = 1;i < n;i++) {
if (temp > num_arr[i]) temp = num_arr[i];
}
return temp;
}
float max_gap(float num_arr[], int n) { #求解最大间隙
float *high = new float[n + 1]; #用于记录每个区间最大值。n个数,总共n+1个区间。
float *low = new float[n + 1]; #用于记录每个区间最小值。
int *count = new int[n +1]; #记录每个区间中数的个数
float max = max_num(num_arr, n);
float min = min_num(num_arr, n);
float dis = max - min;
for (int i = 0;i < n+1;i++) { 对相应值初始化
high[i] =min;
low[i] = max;
count[i] = 0;
}
for (int i = 0;i < n;i++) {
int pos = int((n + 1)*(num_arr[i] - min) / dis); #计算出该数应被分到哪个区#间
count[pos]++;
#更新放入区间的最大最小值
if (high[pos] < num_arr[i])
high[pos] = num_arr[i];
if (low[pos] > num_arr[i])
low[pos] = num_arr[i];
}
float gap = 0;
float low_temp = high[0];
#遍历区间,找到最大间隙。
for (int i = 1;i < n + 1;i++) {
if (count[i]) {
float gap_temp = low[i] - low_temp;
if (gap_temp > gap) {
gap = gap_temp;
low_temp = high[i];
}
}
}
return gap;
}
int main() {
float num_arr[5] = {2.3, 3.1, 7.5, 1.5, 6.3};
int n = 5;
cout << max_gap(num_arr, n) << endl;
int b;
cin >> b;
}
最长交错01子串
如果一个01串任意两个位置的相邻的字符都是不一样的,就叫这个01串为交错01串,要求出一个最长的交错01子串,输入字符串s,和s的长度length。输出子串的长度。
1、这是一个动态规划问题,可以定义一个数组,长度为和s相同,存放到i为止的最长交错01子串长度;
2、到第i个元素为止的子串长度为:若i和i-1的值不一样,子串长度为i-1的子串长度加一,若值相同,子串长度为初始值1;
3、得到数组之后,取其中最大值即为所求的01交错子串的长度。
原文链接:https://blog.youkuaiyun.com/nacl__/article/details/50439482
#include <iostream>
#include<vector>
#include<string>
using namespace std;
int stringlenth(string &s,int length)
{
int i;
vector<int> res(length,1);//向量中有n个1
for(i=1;i<length;i++)
{
if(s[i]!=s[i-1]) //依次比较与前面的一个
{
res[i]=res[i-1]+1; //如果不相等则是前面元素加1
}
}
int maxlong=res[0]; //初始值1
for(i=1;i<length;i++)
{
if(res[i]>maxlong) //把res最大的给maxlong
{
maxlong=res[i];
}
}
return maxlong;
}
int main()
{
string s;
cin>>s;
int length=s.size();
int resnum= stringlenth(s,length);
cout<<resnum<<endl;
return 0;
}
原文链接:https://blog.csdn.net/yige321/article/details/77123781
最长01相等子串(不懂)
定义一个数据B[N], B[i]表示从A[0…i]中 num_of_0 - num_of_1,0的个数与1的个数的差
那么如果A[i] ~ A[j]是符合条件的子串,一定有 B[i] == B[j],因为中间的部分0、1个数相等,相减等于0。 只需要扫一遍A[N]就能把B[N]构造出来了。 这样问题就转换成了求 距离最远的一对数,使得B[i] == B[j],因为B[i]的范围一定是[-N,N],-N到N的范围都存起来,这样每扫到B[i],查数就行了。
int run (char *s)
int n = strlen(s);
vector<int> vec(n,-1);//全部为-1
vec[n]=0;//最后一个为0
int sum = n;
int best = 0; //最长子串数
for (int i = 0; i< n; ++i)
{
if (s[i] == '0') //如果是0就-1,1就加1
{
sum = sum -1;
}
else
{
sum = sum +1;
}
if(vec[sum] >= 0)
{
best = max(best, i - vec[sum] + 1);
}
else
{
vec[sum] = i + 1;
}
}
return best;
}