常见算法题

一、维护O(1)时间查找最大元素的栈

问题描述:一个栈stack,具有push和pop操作,其时间复杂度皆为O(1)。设计算法max操作,

求栈中的最大值,该操作的时间复杂度也要求为O(1)。

可以修改栈的存储方式,push,pop的操作,但是要保证O(1)的时间复杂度,空间时间复杂

度无要求。

 

可以创建一个类,类里有两个栈,一个栈S维持正常的push、pop操作,另一个Sm保存当前的最大值

假设元素以5,4,1,2,3,10,9,8,6,7,15顺序入栈,则两个栈中存储的元素如下图所示:

S    5    4    1    2    3    10    9    8    6    7    15

Sm 5    10  15

struct max_stack{
    stack<int> s1;
    stack<int> sm;
};
max_stack s;
void my_push(int k) {
    if(!s.s1.empty()){
        if(k>s.sm.top()) s.sm.push(k);
        s.s1.push(k);
    } else {
        s.s1.push(k);   s.sm.push(k);
    }
}
void my_pop() {
    if(!s.s1.empty()) {
        if(s.s1.top()==s.sm.top())  s.sm.pop();
        s.s1.pop();
    }
}
int my_max() {
    if(!s.s1.empty()) {
        return s.sm.top();
    }
}

二、约瑟夫环问题

瑟夫环问题的原来描述为,设有编号为1,2,……,n的n(n>0)个人围成一个圈,从第1个人

开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止

报数,报m的出圈,……,如此下去,直到所有人全部出圈为止。当任意给定n和m后,设计

算法求n个人出圈的次序。换一种表述如下

问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始

报数。求胜利者的编号。

具体数学上给出通项公式:

f(0)=0       

f(n)=(f(n-1)+m)%n    ,    (n>1)

int joseph(int n,int m) {
    int *f=new int[n+1];
    f[0]=f[1]=0;
    for(int i=2;i<n+1;i++) 
        f[i]=(f[i-1]+m)%i;
    int result=f[n];
    delete []f;
    return result;
}

如果求解原表述的解,只需要将result加1即可。

三、寻找明星

问题描述:有个聚会有N人参加,其中N-1个是群众。1个是明星。其中所有群众都认识明星,

明星不认识任何群众,群众之前是否认识不知道。

假设有个机器人能问问题A是否认识B?时间复杂度为O(1),那么设计一个算法用最小的复

杂度找出明星。

从问题的描述中可以知道,对于任意两个人A、B,如果A认识B那么A一定不是明星;如果A不

认识B,那么B一定不是明星。将所有人存储在数组中,每次比较询问A[0]是否认识A[1],将一

定不是明星的人放在数组的最后,并且在以后可以不用管了。代码描述如下

int famous(int A[],int n) {
    int j=n;
    while(j>1) {
        if(A[0] knows A[1]) 
            swap(A[0],A[1]);
        swap(A[1],A[--j]);
    }
    return A[0];
}

由于询问和交换的时间复杂度是O(1),while循环进行了n-1次,所以时间复杂度是O(n).

四、最小交流次数

问题描述:有n个战士其中n>4他们手中都有不同的情报,假设每个人通过交流能过得双方所有

的情报。设计一个算法使得用最少的交流次数使得所有的战士都获得全部的情报,给出算法并

给出最小交流次数?

 

可以建立递推式:

                       f(4)=4

                       f(n)=f(n-1)+2  ,  n>4

假设在战士人数是n-1时需要f(n-1)次交流,则增加一个人时,如下步骤进行:

1、第n个战士和前面任意一个战士交流一次

2、前n-1个战士互相交流,使得前面n-1个战士都有所有战士获得的情报

3、第n个战士和前面任意一个战士交流一次。

这样n个战士都有所有情报了。

五、数星星

问题描述:A和B晚上无聊就开始数星星。每次只能数K个(20<=k<=30)A和B轮流数。最后

谁把星星数完谁就获胜,那么当星星数量为多少时候A必胜?

这是一个博弈的问题,我们可以从胜利条件出发,A必胜,那么最后一次是A数,并且剩下星星

的个数 20<=k<=30 ,那么如何保证呢?最后50颗由B先数,B数m颗,然后A数剩下的50-m

颗。好了,那么第一次A数的话必须保证,第一次A数完之后,剩下的个数是50的倍数。所以

案就明了了,星星的数量应满足    

50k+20 <= N <=50K+30    ,    k是整数

六、求连续子数组的最大和

这是一个动态规划问题递推式为

M(i)=max{M(i-1)+a(i),a(i)},i>0

int max_sub_sum(int *A,int n) {
    int thissum=0,maxsum=0;
    for(int i=0;i<n;i++) {
        thissum+=A[i];
        if(thissum>maxsum)    maxsum=thissum;
        if(thisum<0)          thisum=0;
    }
    return maxsum;
}

七、二分查找

用二分法查找已排序的大小为n的数组A是否存在value,如果存在返回下标,否则返回-1。

int b_search(int *A,int n,int value) {
    int low=0,high=n-1;
    while(low<=high) {
        int mid=(low+high)/2;
        if(A[mid]==value)        return mid;
        else if(A[mid]>value)    high=mid-1;
        else                     low=mid+1;
    }
    return -1;
}
 
转自:http://blog.csdn.net/xhl9317273572010xhl/article/details/8911736
 
八、分糖果
有n个小朋友坐成一圈,每人有Ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1,求使所有人获得均等糖果的最小代价。设Xi为第i-1个小朋友分给第i个小朋友的糖果数,G为最后的平均数。其中X1为第n个小朋友分给第1个小朋友的糖果数。

A1 +X1 + X2 = G

A2 + X2 - X3 = G

.

An + Xn - X1 = G

解得

X1 = X1

X2 = A1 - G - X1

X3 = A1 + A2 - G - G + X1

.

Xn = A(n-1)+A(n-2)+...A2+A1 - (n -1)* G + X1

则总开销为:|X1|+|X2|+...+|Xn| =|X1|+ |A1-G+X1| + |A2+A1-2*G+X1| + ... +|A(n-1)+A(n-2)+...A2+A1 - (n -1)* G + X1|

设s[i]=Ai+ ... +A1- i*G; 则上式=|X1| + ∑|s[i]+X1|    ,1=< i<=n-1

设k为第一个分给第n个的数量为k,则k=-X1,上式为:|k| + ∑|s[i]-k| ,1=< i<=n-1

要使上式值最小,则k为0, s[1], s[2], ......s[n-1]的中位数。

这主要是利用了中位数的一个性质:数组中数与中位数差的绝对值和最小。

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <algorithm>
 4 using namespace std;
 5 const long long N = 2001000;
 6 long long a[N], s[N], tar[N], n;
 7 int main ()
 8 {
 9     scanf ("%d", &n);
10     for (long long i = 1; i <= n; i ++)
11         scanf ("%d", &a[i]), s[i] = s[i - 1] + a[i];
12     long long g = s[n] / n;
13     for (long long i = 1; i < n; i ++)
14         tar[i] = i * g - s[i];
15     sort (tar + 1, tar + 1 + n);
16     long long x = n >> 1, z = abs(tar[x]);
17     for (long long i = 1; i <= n; i ++)
18         z += abs (tar[i] - tar[x]);
19     printf ("%lld\n", z);
20     return 0;
21 }
转自:http://blog.csdn.net/stormbjm/article/details/8911396

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值