校招季——编程题目(15、16) 约瑟夫问题 最大子矩阵和

来源:互联网 发布:薛之谦 上海炮王 知乎 编辑:程序博客网 时间:2024/05/07 15:37

15.      约瑟夫问题(题目042

题目:

n个人围成一圈,从第一个开始报数,第m个将被杀掉,最后剩下一个,其余人都将被杀掉。求最后剩下的人的序号。例如n=6m=5,被杀掉的人的序号为54623。最后剩下1号。

解答:

思路:

如果要打印整个过程,有3种方法:

1.     链表法:产生长度为n的循环链表,然后每遍历m次输出当前序号,并删除节点,直到链表中只有一个元素为止。

2.     数组法:创建一个辅助数组,初始都为0,然后每遍历m个为0的位置就输出当前序号,并将该位置的值改为1,直到数组大小变成1为止。

3.     数组法:创建一个辅助数组,其中保存编号,每删除一个就将后面的编号前移。

3种方法的时间复杂度都是O(n*m),如果只需要输出最后的序号,则可以利用一些数学手段寻找规律,简化过程。

为了简化问题,我们假定序号从0开始。

对于n个人的情况,第1个杀掉的人肯定是(m-1)%n号,这时剩下的人记为mm+1,…,n-10,…,m-2,将它们重新记为012,…,n-2,其中的对应关系为:

X = (x’ + m) % n

其中xn个人时的序号,x’n-1个人时的序号,令f(n)n个人时最后剩余的人的序号,则f(n)和此时的f(n-1)应该对应着同一个人,且其编号有如上式的对应关系,即:

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

其初始条件为f(1)=0。返回结果时再将f(n)+1,从而变换成序号从1开始的情况。

int Josephus(int n, int m){    int result = 0, i;    for (i = 2; i <= n; ++i)        result = (result + m) % i;    return result + 1;}

16.      最大子矩阵和(题目052

题目:

输入一个M*N的矩阵,其中每个元素为有正有负的整数,输出它的最大的子矩阵元素和。如果不存在矩阵和为正数的子矩阵,返回0

解答:

方法1

简单的三重循环求每个子矩阵的矩阵和,返回最大值,时间复杂度O(m3n3)

方法2

定义一个大小也为m*n的新矩阵sub_sum,其中sub_sum[i][j]表示子矩阵{0,0}~{i,j}的矩阵和。

sub_sum[i][j] = sub_sum[i-1][j] + sub_sum[i][j-1] - sub_sum[i-1][j-1] + mt[i][j];

则对任意子矩阵{a,b}~{c,d},它的矩阵和为:

sum = sub_sum[c][d] - sub_sum[c][b-1] - sub_sum[a-1][d] + sub_sum[a-1][b-1];

总的时间复杂度为O(m2n2)

方法3

利用最大子序列和的性质,求出[si, ei]范围内每列的和,再从其中找出最大连续子序列的和,就是要求的结果。时间复杂度O(mn2)

int MaxSubMatrixSum(const Matrix *mt){    int rows = mt->rows, cols = mt->cols ,size = cols * sizeof(int);    int *col_sum = malloc(size);    int si, ei, j, max_sum = 0;    for (si = 0; si < rows; ++si)    {        memset(col_sum, 0, size);        for (ei = si; ei < rows; ++ei)        {            for (j = 0; j < cols; ++j)                col_sum[j] += mt->data[ei][j];            int sum = MaxSum(col_sum, cols);            if (sum > max_sum)                max_sum = sum;        }    }    return max_sum;}

原创粉丝点击