奇虎360 2017春招编程题

总结:三道编程题都还是比较简单的,但是我不停地花式犯错导致只对了第一道编程题(往事不堪回首,说好的细心呢?),看来是无缘面试了。。。
PS:有很多问题本来想在面试时说的,不料小错误不断,无缘面试。。。
①官方提供的简历模版在选择学校时并没有我们学校,用户体验不好
②官网底部的校招和社招链接没有实时更新,甚至链接2013年的信息网址。
③笔试题细节问题也有:选择题中println中输出有空格,而所给的选项只有一个错误选项含有空格,其余的没有按照格式输出;编程题所给的限制与结束后给定的限制不同,一定程度上会造成对错误原因的误判而从错误的方向调试。

1. 跑步

题目链接

题目

小明同学喜欢体育锻炼,他常常去操场上跑步。跑道是一个圆形,在本题中,我们认为跑道是一个半径为 R R 的圆形,设圆心的坐标为原点(0,0)
小明跑步的起点坐标为 (R,0) ( R , 0 ) ,他沿着圆形跑道跑步,而且一直沿着一个方向跑步。回到家后,他查看了自己的计步器,计步器显示他跑步的总路程为 L L
小明想知道自己结束跑步时的坐标,但是他忘记自己是沿着顺时针方向还是逆时针方向跑的了。他想知道在这两种情况下的答案分别是多少。

思路 - 几何

根据扇形周长公式可知:走过的角度(弧度制)angle=LR
则可直接算出坐标:
①逆时针:( Rcos(angle),Rsin(angle) R ∗ c o s ( a n g l e ) , − R ∗ s i n ( a n g l e ) )
②顺时针:( Rcos(angle),Rsin(angle) R ∗ c o s ( a n g l e ) , R ∗ s i n ( a n g l e ) )

代码

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        double l, r, x, y, angle;
        while(input.hasNext()) {
            l = input.nextDouble();
            r = input.nextDouble();
            angle = l / r;
            x = r * Math.cos(angle);
            y = r * Math.sin(angle);
            System.out.printf("%.3f %.3f", x, -y);
            System.out.println();
            System.out.printf("%.3f %.3f", x, y);
            System.out.println();
        }

        input.close();
    }

}

2. 剪气球串

题目链接

题目

小明买了一些彩色的气球用绳子串在一条线上,想要装饰房间,每个气球都染上了一种颜色,每个气球的形状都是各不相同的。 199 我 们 用 1 到 9 一 共 9 个 数 字 表 示 不 同 的 颜 色 ,如 12345 12345 则表示一串 5 5 个颜色各不相同的气球串。但小明希望得到不出现重复颜色的气球串,那么现在小明需要将这个气球串剪成多个较短的气球串,小明一共有多少种剪法?1234512345
注意每种剪法需满足最后的子串中气球颜色各不相同(如果满足该条件,允许不剪,即保留原串)。两种剪法不同当且仅当存在一个位置,在一种剪法里剪开了,而在另一种中没剪开。详见样例分析。

思路 - DP

求方案数,很明显是 DP D P ,很容易就能想到常数为 9 9 O(n)的做法,设 dp[i] d p [ i ] 表示前 i i 个气球能形成的方案数,dp[i]=dp[j],其中区间 [j,i] [ j , i ] 不含重复的气球,从后往前开始判断,最多循环 9 9 次。

清楚地记得测试时C++限时 1ms 1 m s ,限制空间 128KB 128 K B ,但是出来就变成限时 2000ms 2000 m s ,限空间 128MB 128 M B 了。。。
因为申请的是 Java J a v a 开 发 工 程 师 ,所以用 Java J a v a 写题(犯的第一个错误)。
虽然 Java J a v a 空间限制比较送,但是还是想按 C++ C + + 的空间限制做(犯的第二个错误),就取模只看最近的 10 10 个,导致下标要从 0 0 开始,然后各种下标中取模,又导致写搓了,结果很难看出错误,电脑用Java调试又比较卡,就用 println p r i n t l n 大法。。。最终当然是没有调试流畅,导致没发现错误,惨败

结束后发现:把 vis[num[jj]] v i s [ n u m [ j j ] ] 写成 vis[jj] v i s [ j j ]

代码

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        int n, ii, jj;
        int[] num = new int[11];
        int[] dp = new int[11];
        boolean[] vis = new boolean[11];
        while(input.hasNext()) {
            n = input.nextInt();
            num[0] = input.nextInt();
            dp[9] = dp[0] = 1;
            for(int i = 1; i < n; ++i) {
                for(int j = 1; j <= 9; ++j) {
                    vis[j] = false;
                }
                ii = i % 10;
                num[ii] = input.nextInt();
                vis[num[ii]] = true;
                dp[i % 10] = dp[(i - 1) % 10];
                for(int j = 1; j < 9 && i >= j; ++j) {
                    jj = (i - j) % 10;
                    if(vis[num[jj]]) {
                        break;
                    }
                    dp[ii] = dp[ii] + dp[(jj + 9) % 10];
                    if(dp[ii] >= 1000000007) {
                        dp[ii] -= 1000000007;
                    }
                    vis[num[jj]] = true;
                }
            }
            System.out.printf("%d", dp[(n - 1) % 10]);
            System.out.println();
        }

        input.close();
    }

}

3. 分金子

题目链接

题目

AB A 、 B 两伙马贼意外地在一片沙漠中发现了一处金矿,双方都想独占金矿,但各自的实力都不足以吞下对方,经过谈判后,双方同意用一个公平的方式来处理这片金矿。处理的规则如下:他们把整个金矿分成 n n 段,由AB开始轮流从最左端或最右端占据一段,直到分完为止。
马贼 A A 想提前知道他们能分到多少金子,因此请你帮忙计算他们最后各自拥有多少金子?(两伙马贼均会采取对己方有利的策略)

思路 - 区间DP

dp[l][r]表示先手在区间 [l,r] [ l , r ] 最多能取的数的和,则状态转移方程为:
dp[l][r]=max(num[l]+dp[l+1][r],num[r]+dp[l][r1]) d p [ l ] [ r ] = m a x ( n u m [ l ] + d p [ l + 1 ] [ r ] , n u m [ r ] + d p [ l ] [ r − 1 ] )

最简单的区间 DP D P ,随手就写了一个记忆化搜索方式的,结果 TLE T L E ,由于当时第二题还没写,就先不管了,以为要 O(nlogn) O ( n l o g n ) 的解法才行。

结束后才发现递归返回时没有给 dp d p 赋值。。。(我一定是个“存盘退出”)

代码

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        int T = input.nextInt(), kase = 0;
        int n, ans;
        int[] sum = new int[503];
        int[][] dp = new int[503][503];

        while(kase++ < T) {
            n = input.nextInt();
            sum[0] = 0;
            for(int i = 1; i <= n; ++i) {
                sum[i] = sum[i - 1] + input.nextInt();
                for(int j = 1; j <= n; ++j) {
                    dp[i][j] = -1;
                }
            }
            ans = getAns(sum, dp, 1, n);
            System.out.printf("Case #%d: %d %d", kase, ans, sum[n] - ans);
            System.out.println();
        }

        input.close();
    }

    private static int getAns(int[] sum, int[][] dp,int l, int r) {
        if(dp[l][r] != -1) {
            return dp[l][r];
        }
        if(l == r) {
            return sum[r] - sum[l - 1];
        }
        return dp[l][r] = sum[r] - sum[l - 1] - Math.min(getAns(sum, dp, l + 1, r) , getAns(sum, dp, l, r - 1));
    }

}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值