2019/04/05 腾讯笔试 后台及综合卷(java)

AC1.8(0.1+1.0+0.7),很菜,第三次笔试。

前两次笔试(百度2019/04/02,拼多多2019/04/03)的时候,有些题目看完连反应都没有,智商被按在地上摩擦,心态大崩。

痛定思痛,刷了两天算法题,算是有点小小进步,至少今晚三道题目都有点感觉。

 

记录一下,如果有人讨论一下就更好了。

 

1.(AC0.1)给定n,m,是否能够利用n种不同面值的硬币组成1到m总值,如果可以输出最少需要几个硬币,不可以输出-1。

例如:n=4,m=20,n种面值硬币:1,2,5,10  输出5

笔试时想法:

      两层嵌套循环,maxCount来统计至少需要多少数量的硬币;从钱总值a   从1到m;数量c来统计钱总值a至少需要多少硬币;硬币的面值b从大到小进行遍历,c=c+a/b,a=a%b,循环完判断一下a是否为0,是则继续循环,否则返回-1;如果c>maxCount,将maxCount=c。

      漏洞:比如19=10*1+5*1+2*2(count=4)18=10*1+5*1+2*1+1*1(count=4),但是以19的面值组成成分没法组成18,dead。

 

现在想法(刚考完):(目前还未发现有啥漏洞)

      两层嵌套循环,map1来统计各个面值硬币一共需要多少个;从钱总值a   从1到m;map2来统计钱总值a,各个面值硬币需要多少个;硬币的面值b  从大到小进行遍历,map的面值b中放入a/b,a=a%b;更新map1,如果map2某个面值需要的数量大于map1则更新,map1为大的那个值,并且统计一下map1中全部加起来的总值sum,在后续遍历中,如果钱总值a小于sum则直接跳过,不遍历。最后,统计一下map1中所有面值需要的数量总和,输出。

------------------------------------------------------2019/04/07更新---------------------------------------------------------

其实上面不用使用map,可以直接用数组来记录,更新了一下代码。

并为上面思路画了一个草图(一部分),方便大家理解,使用的栗子:以n=4,m=20,n种面值硬币:1,2,5,10  输出5

     代码:

import java.util.Arrays;
import java.util.Scanner;
public class Coin {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int m = in.nextInt();
        int n = in.nextInt();
        int[] ns = new int[n];
        for(int i=0;i<n;i++) ns[i] = in.nextInt();
        Arrays.sort(ns);//排序硬币
        /*
	       最小面值大于1,直接返回-1,因为1首先就没法组合出来,
	       其实只要有面值为1的硬币,什么都可以组合出来
        */
        if(ns[0]>1 ) {
            System.out.println(-1);
            return;
        }
        long[] result = new long[n];//result记录总共各面值需要的数量
        int sum = 0;//result所有面值加起来的总和sum
        for(int i=1;i<=m;i++) {
        	if(i<=sum) continue;//钱总和 i 小于sum,就直接跳过
        	int money = i;//当前要组成钱总值
        	for(int j=n-1;j>=0;j--) {
        		if(money/ns[j] != 0) {
        			//当需要第j枚硬币的数量大于result第j枚硬币数量,则更新result中数量
        			if(money/ns[j] > result[j]) result[j] = money/ns[j];
        			money = money%ns[j];
        		}
        		if(money == 0) break;
        	}
            //计算新的sum
        	sum = 0;
        	for(int k=0;k<n;k++) {
        		sum += result[k]*ns[k];
        	}
        }
        //统计总共需要多少个硬币
        int count = 0;
        for (long c : result) count += c;
        System.out.println(count);
    }
}

 

2.(AC1.0)给定一个字符串,只有1和0,如果相邻的两个字符分别为1和0,则可以抵消,一直执行下去,问字符串最后剩下几个字符。(送分题)

想法:

       统计字符串中0的数量A和1的数量B,返回A-B的绝对值。

(太简单了,就不贴代码了)

 

3.(AC0.7)你要穿过山谷,前面有n只怪兽,怪兽i你可以花费pi来收买它,它会护送你穿过山谷,如果遇到一个怪兽j,它的战斗力是dj,护送你的全部怪兽加起来的战斗力大于dj,你不需要收买它,否则你需要收买它才能通过。问你最少需要多少钱来穿过山谷。

     如,输入n=4,d[]={1,2,4,8} p={1,2,1,2} 输出 6

            输入n=3,d[]={8,5,10} p={1,1,2} 输出2

笔试时想法:

       变量maxIndex来表示最大怪兽的下标,变量left表示要战胜最大怪兽的战斗值,怪兽从后往前遍历,如果碰到怪兽的武力值大于left就更新maxIndex和left;收不收买当前的怪兽i取决于怪兽i之前的怪兽的战斗力加起来是否大于d[maxIndex],大于等于则当前怪兽就可以不收买,小于收买,left=left-怪兽i武力值。

漏洞:好像没有考虑到收买的钱,只考虑能不能打败怪兽(●—●),具体怎么改还没有想法

------------------------------------------------------2019/04/07更新---------------------------------------------------------

       看了牛客网很多帖子,正解应该是深度搜索+剪枝,但是题目的n是10^12,所以解空间很大,会花费很多时间。这里贴一个牛客网大佬AC的代码,思路就是当怪兽i通过不了的时候就比较两个条件①收买怪兽i的钱+当前已经花费的钱是否大于收买怪兽i之前全部怪兽的钱②怪兽i之前的全部怪兽的武力值总和是否大于怪兽i的武力值,两个条件为true则收买怪兽i之前全部怪兽,否则收买怪兽i。

注明出处:

作者:永航     链接:https://www.nowcoder.com/discuss/173782?type=0&order=0&pos=6&page=1
 

代码:


import java.util.Scanner;

public class Third {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        long[] powers = new long[n];
        long[] moneys = new long[n];

        for (int i = 0; i < n; i++) {
            powers[i] = sc.nextLong();
        }

        for (int i = 0; i < n; i++) {
            moneys[i] = sc.nextLong();
        }

        long currPower = 0;
        long totalMoney = 0;

        for (int i = 0; i < n; i++) {
            if (currPower < powers[i]){
                if ((totalMoney+moneys[i]) > sum(moneys,0,i-1) &&powers[i] < sum(powers,0,i-1)){
                    totalMoney = sum(moneys,0,i-1);
                    currPower = sum(powers,0,i-1);
                    continue;
                }
                totalMoney += moneys[i];
                currPower += powers[i];
            }else{
                continue;
            }
        }

        System.out.println(totalMoney);
    }
    private static long sum(long[] arr, int start, int end){
        long sum = 0;
        for (int i = start; i <= end; i++){
            sum += arr[i];
        }
        return sum;
    }

 

2019/04/06  0:17 记录一下笔试时候的想法,希望后续通过自己或社区可以得到这三道题的AC1.0的解法。

2019/04/08  0:26 更新了第一题帮助理解的草图,第三题一个AC的代码

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值