【九度】2014年王道论坛研究生机试练习赛第三场解题报告

108 篇文章 0 订阅
102 篇文章 5 订阅
1、题目1527:首尾相连数组的最大子数组和
时间限制:1 秒内存限制:128 兆特殊判题:否提交:1557解决:268
题目描述:
给定一个由N个整数元素组成的数组arr,数组中有正数也有负数,这个数组不是一般的数组,其首尾是相连的。数组中一个或多个连续元素可以组成一个子数组,其中存在这样的子数组arr[i],…arr[n-1],arr[0],…,arr[j],现在请你这个ACM_Lover用一个最高效的方法帮忙找出所有连续子数组和的最大值(如果数组中的元素全部为负数,则最大和为0,即一个也没有选)。
输入:
输入包含多个测试用例,每个测试用例共有两行,第一行是一个整数n(1=<n<=100000),表示数组的长度,第二行依次输入n个整数(整数绝对值不大于1000)。
输出:
对于每个测试用例,请输出子数组和的最大值。
样例输入:
6
1 -2 3 5 -1 2
5
6 -1 5 4 -7
样例输出:
10
14
来源:
淘宝2013年校园招聘一面面试题
解题思路:1、我看到其他人有在写,但是我觉得他们写的好像很复杂的样子。其实应该不难,暴力搜索的话,复杂度应该是O(N*N),将循环数组看成两个拼接起来的数组,然后针对每个i求最大连续子数组和。速度有点慢,可以参考其余大神们80ms的代码。
2、关于首尾相连数组的最大子数组和,这个有两种情况,1)、首尾不相连的数组中最大子数组和。2)、首尾相连的数组中,最大子数组和是所有数子和减去最小子数组和。这个时间复杂度是o(n),好像面试官会比较喜欢这种解题思路?

1、Java AC

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
 
public class Main {
    /*
     * 1527
     */
    public static void main(String[] args) throws Exception {
        StreamTokenizer st = new StreamTokenizer(new BufferedReader(
                new InputStreamReader(System.in)));
        while (st.nextToken() != StreamTokenizer.TT_EOF) {
            int n = (int) st.nval;
            int len = 2 * n;
            int array[] = new int[len];
 
            for (int i = 0; i < n; i++) {
                st.nextToken();
                array[i] = (int) st.nval;
                array[i + n] = array[i];
            }
            int sum = 0;
            for (int i = 0; i < (i + n) && (i + n) <= len; i++) {
                int tempSum = array[i];
                if (tempSum > sum) {
                    sum = tempSum;
                }
                for (int j = i + 1; j < (i + n); j++) {
                    if (tempSum < 0) {
                        break;
                    } else {
                        tempSum += array[j];
                    }
                    if (tempSum > sum) {
                        sum = tempSum;
                    }
                }
            }
            System.out.println(sum);
        }
    }
}
 
/**************************************************************
    Problem: 1527
    User: wangzhenqing
    Language: Java
    Result: Accepted
    Time:1110 ms
    Memory:25440 kb
****************************************************************/
1、C++ AC
#include <stdio.h>
const int maxn = 200002;
int n,i;
int array[maxn];
int main(){
    while(scanf("%d",&n) != EOF){
        int len = 2*n;
        for(i = 0; i < n; i++){
            scanf("%d",&array[i]);
            array[i+n] = array[i];
        }
        int sum = 0;
        for (i = 0; i < (i + n) && (i + n) <= len; i++) {
            int tempSum = array[i];
            if (tempSum > sum) {
                sum = tempSum;
            }
            for (int j = i+1; j < (i + n ); j++) {
                if (tempSum < 0) {
                    break;
                }else {
                    tempSum += array[j];
                }
                if (tempSum > sum) {
                    sum = tempSum;
                }
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}
/**************************************************************
    Problem: 1527
    User: wzqwsrf
    Language: C++
    Result: Accepted
    Time:220 ms
    Memory:1800 kb
****************************************************************/

2、Java AC

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
  
public class Main {
    /*
     * 1527
     */
    public static void main(String[] args) throws Exception {
        StreamTokenizer st = new StreamTokenizer(new BufferedReader(
                        new InputStreamReader(System.in)));
        while (st.nextToken() != StreamTokenizer.TT_EOF) {
            int n = (int) st.nval;
            int array[] = new int[n];
            int sum = 0;
            st.nextToken();
            array[0] = (int) st.nval;
            sum += array[0];
            int maxValue = array[0] > 0 ? array[0] : 0;
            int minValue = array[0] < 0 ? array[0] : 0;
            int max = maxValue;
            int min = minValue;
            for (int i = 1; i < n; i++) {
                st.nextToken();
                array[i] = (int) st.nval;
                if (maxValue > 0) {
                    maxValue += array[i];
                }else {
                    maxValue = array[i];
                }
                if (minValue < 0) {
                    minValue += array[i];
                }else {
                    minValue = array[i];
                }
                max = maxValue > max ? maxValue : max;
                min = minValue < min ? minValue : min;
                sum += array[i];
            }
            int temp = sum - min;
            System.out.println(max > temp ? max : temp);
        }
    }
}
 
/**************************************************************
    Problem: 1527
    User: wangzhenqing
    Language: Java
    Result: Accepted
    Time:860 ms
    Memory:28876 kb
****************************************************************/
2、C++ AC

#include <stdio.h>
const int maxn = 100002;
int n,i;
int array[maxn];
int main(){
    while(scanf("%d",&n) != EOF){
        scanf("%d",&array[0]);
        int sum = 0;
        sum += array[0];
        int maxValue = array[0] > 0 ? array[0] : 0;
        int minValue = array[0] < 0 ? array[0] : 0;
        int max = maxValue;
        int min = minValue;
        for(i = 1; i < n; i++){
            scanf("%d",&array[i]);
            if (maxValue > 0) {
                maxValue += array[i];
            }else {
                maxValue = array[i];
            }
            if (minValue < 0) {
                minValue += array[i];
            }else {
                minValue = array[i];
            }
            max = maxValue > max ? maxValue : max;
            min = minValue < min ? minValue : min;
            sum += array[i];
        }
        int temp = sum - min;
        printf("%d\n",max > temp ? max : temp);
    }
    return 0;
}
/**************************************************************
    Problem: 1527
    User: wzqwsrf
    Language: C++
    Result: Accepted
    Time:70 ms
    Memory:1412 kb
****************************************************************/
2、 题目1537:买卖股票

时间限制:1 秒内存限制:128 兆特殊判题:否提交:461解决:117
题目描述:
给定一个大小为n的数组,数组的元素a[i]代表第i天的股票价格。
设计一个算法,计算在最多允许买卖k次(一买一卖记为一次)的条件下的最大收益。
需要注意的是,你不能同时拥有两份股票。也就是说在下次买入前,你必须把手头上原有的股票先卖掉。
输入:
输入可能包含多个测试案例。
对于每个测试案例,输入的第一行为两个整数n和k(1<=n,k<=1000)。
输入的第二行包括n个整数,范围在[0,10000),代表数组中的元素。
输出:
对应每个测试案例,输出最大获益。
样例输入:
5 1
3 4 5 1 4
7 2
1 2 3 5 6 1 7
样例输出:
3
11
来源:
Leetcode 加强版本
解题思路:这个在 http://t.jobdu.com/thread-101867-1-1.html鬼M大神有写思路。
第j天交易i次的最大利润,dp[i][j]
dp[i][j] = max{dp[i-1][m]+price[j]-price[m]}(1 <= m < i);
dp[i-1][m]+a[j]-a[m]如果改写成
dp[i-1][m]-a[m]+a[j]
前面一部分dp[i-1][m]-a[m]和j是无关的
也就是说到dp[j]的时候,只要知道前面dp[i-1][m]-a[m]的最大值即可。
所以我们维护dp[i-1][m]-a[m]最大值。

Java AC

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
   
public class Main {
     /*
     * 1537
     */
    public static void main(String[] args) throws Exception{
        StreamTokenizer st = new StreamTokenizer(
        		new BufferedReader(new InputStreamReader(System.in)));
        while (st.nextToken() != StreamTokenizer.TT_EOF) {
            int n = (int) st.nval;
            st.nextToken();
            int k = (int) st.nval;
            int array[] = new int[n+1];
            for (int i = 1; i < n+1; i++) {
                st.nextToken();
                array[i] = (int) st.nval;
            }
            int size = 1002;
            int dp[][] = new int[size][size];
            int result = 0;
            int tempValue = Integer.MIN_VALUE;
            for (int i = 1; i < k+1; i++) {
                tempValue = dp[i-1][1] - array[1];
                for (int j = 2; j < n+1; j++) {
                    dp[i][j] = Math.max(tempValue+array[j], dp[i][j-1]);
                    result = Math.max(dp[i][j], result);
                    tempValue = Math.max(tempValue, dp[i-1][j]-array[j]);
                }
            }
            System.out.println(result);
        }
    }
}
/**************************************************************
    Problem: 1537
    User: wangzhenqing
    Language: Java
    Result: Accepted
    Time:600 ms
    Memory:71720 kb
****************************************************************/
C++ AC
#include <stdio.h>
#include <string.h>
const int maxn = 1002;
int array[maxn];
int dp[maxn][maxn];
int max(int a, int b){
    return a > b ? a : b;
}
int main(){
    int n,k,i;
    while(scanf("%d%d",&n,&k)!=EOF){
        for(i = 1; i < n+1; i++){
            scanf("%d",&array[i]);
        }
        memset(dp,0,sizeof(dp));
        int result = 0;
        int tempValue = 99999999;
        for (i = 1; i < k+1; i++) {
            tempValue = dp[i-1][1] - array[1];
            for (int j = 2; j < n+1; j++) {
                dp[i][j] = max(tempValue+array[j], dp[i][j-1]);
                result = max(dp[i][j], result);
                tempValue = max(tempValue, dp[i-1][j]-array[j]);
            }
        }
        printf("%d\n", result);
    }
    return 0;
}
 
/**************************************************************
    Problem: 1537
    User: wzqwsrf
    Language: C++
    Result: Accepted
    Time:90 ms
    Memory:4948 kb
****************************************************************/
3、题目1551:切蛋糕

时间限制:1 秒内存限制:128 兆特殊判题:否提交:211解决:59
题目描述:

有如下图半价为R的圆形蛋糕,被切一刀后(图中红色直线),分成两个部分(黄色和绿色),已知其比例为r,求刀痕长度(图中红色直线)。


输入:
输入包括多组测试数据,包括一个整数R(1<=R<=1000),和一个浮点数r(0<r<1),精确到第四位小数。
输出:
对于每组测试用例,输出一个浮点数,代表刀痕的长度,保留二位小数。
样例输入:
1000 0.5000
500 0.6183
样例输出:
1928.53
982.49
来源:
2014年王道论坛研究生机试练习赛(三)
解题思路:这个需要知道扇形面积计算公式,
1、s = |a|*R*R/2,其中R为半径,a为扇形对应的角度。二分查找,无限逼近。
2、假设切痕长度为mid,那么角度a = asin(mid/(2*R)),三角形面积为s1 = (mid/2)*sqrt(R*R-mid*mid/4);
3、则黄色部分的面积为l = s - s1,绿色部分面积为b = PI*R*R-l;
4、比例为l/b,如果l/R > r,则说明mid太大了,high = mid,否则的话low = mid;

Java AC

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
 
public class Main {
    /*
     * 2014年3月9日 22:55:47
     */
    public static void main(String[] args) throws IOException {
        StreamTokenizer st = new StreamTokenizer(new BufferedReader(
                new InputStreamReader(System.in)));
        while (st.nextToken() != StreamTokenizer.TT_EOF) {
            int R = (int) st.nval;
            st.nextToken();
            double r = st.nval;
            double low = 0.0;
            double high = 2 * R;
            double mid = 0;
            while ((high - low) >= 0.0001) {
                mid = (low + high) / 2;
                if (countArea(R, mid) > r) {
                    high = mid;
                } else {
                    low = mid;
                }
            }
            System.out.printf("%.2f\n", mid);
        }
    }
 
    public static double countArea(double R, double mid) {
        double du = Math.asin(mid / (2 * R));
        double l = R * R * du - 0.5 * mid * Math.sqrt(R * R - 0.25 * mid * mid);
        double r = R * R * Math.PI - l;
        return l / r;
    }
}
 
/**************************************************************
    Problem: 1551
    User: wzqwsrf
    Language: Java
    Result: Accepted
    Time:380 ms
    Memory:15160 kb
****************************************************************/
C++ AC
#include <stdio.h>
#include <math.h>
#define PI 3.1415926
 
double countArea(double R, double mid) {
    double du = asin(mid / (2 * R));
    double l = R * R * du - 0.5 * mid * sqrt(R * R - 0.25 * mid * mid);
    double r = R * R * PI - l;
    return l / r;
}
 
int main(){
    int R;
    double r;
    while(scanf("%d%lf",&R,&r)!=EOF){
        double low = 0.0;
        double high = 2 * R;
        double mid = 0;
        while ((high - low) >= 0.0001) {
            mid = (low + high) / 2;
            if (countArea(R, mid) > r) {
                high = mid;
            } else {
                low = mid;
            }
        }
        printf("%.2lf\n", mid);
    }
    return 0;
}
 
/**************************************************************
    Problem: 1551
    User: wzqwsrf
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1100 kb
****************************************************************/
4、题目1552:座位问题

时间限制:1 秒内存限制:128 兆特殊判题:否提交:208解决:51
题目描述:
计算机学院的男生和女生共n个人要坐成一排玩游戏,因为计算机的女生都非常害羞,男生又很主动,所以活动的组织者要求在任何时候,一个女生的左边或者右边至少有一个女生,即每个女生均不会只与男生相邻。现在活动的组织者想知道,共有多少种可选的座位方案。
例如当n为4时,共有
女女女女, 女女女男, 男女女女, 女女男男, 男女女男, 男男女女, 男男男男
7种。
输入:
输入包含多组测试用例,每组测试用例仅包含一个整数n(1<=n<=1000)。
输出:
对于每组测试用例,输出一个数代表可选的方案数,为防止答案过大,答案对1000000007取模。
样例输入:
1
2
4
样例输出:
1
2
7
来源:
2014年王道论坛研究生机试练习赛(三)
解题思路:这个好像是dp,dp[i] = dp[i-1] + dp[i-2] + dp[i-4]。

Java AC

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
 
public class Main {
    /*
     * 2014年3月9日 21:05:41
     */
    public static void main(String[] args) throws IOException {
        StreamTokenizer st = new StreamTokenizer(new BufferedReader(
                new InputStreamReader(System.in)));
        while (st.nextToken() != StreamTokenizer.TT_EOF) {
            int n = (int) st.nval;
            long dp[] = new long[1002];
            int mod = 1000000007;
            dp[1] = 1;
            dp[2] = 2;
            dp[3] = 4;
            dp[4] = 7;
            for (int i = 5; i <= n; i++) {
                dp[i] = (dp[i-1] + dp[i-2] + dp[i-4]) % mod;
            }
            System.out.println(dp[n]);
        }
    }
}
 
/**************************************************************
    Problem: 1552
    User: wzqwsrf
    Language: Java
    Result: Accepted
    Time:440 ms
    Memory:17796 kb
****************************************************************/

C++ AC

#include <stdio.h>
#include <string.h>
const int maxn = 1002;
long dp[maxn];
  
int main(){
    int mod = 1000000007;
    dp[1] = 1;
    dp[2] = 2;
    dp[3] = 4;
    dp[4] = 7;
    for (int i = 5; i <= 1000; i++) {
        dp[i] = (dp[i-1] + dp[i-2] + dp[i-4]) % mod;
    }
    int n;
    while(scanf("%d",&n)!=EOF){
        printf("%d\n", dp[n]);
    }
    return 0;
}
 
/**************************************************************
    Problem: 1552
    User: wzqwsrf
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1028 kb
****************************************************************/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值