网易8-11笔试算法题解析

2 篇文章 0 订阅
1 篇文章 0 订阅

8-11 网易笔试算法

记一次网易笔试算法题解题思路,由于原题目描述太形象化了,这里题目描述就开门见山了。所知题目就5个(应该还有但是我找不到啊o(╯□╰)o)其中加法乘法和游戏很容易这里就不给出了。

瞌睡题

题目描述

给定一个数组数组的每一个位置代表一个分值,同时给定同样长度的数组每个位置都是0或1代表分值数组对应位置是否能获取(1可以,0不行),给定整形k代表可以叫醒k分钟,即从任意位置开始连续k个位置的分值都可以加上,而不管对应位置是否为1或0,在只能叫醒一次时求可以获得的分值的最大值

输入
  • n,k代表数组长度,和叫醒一次能醒的时间
  • n个数代表各个时间的分值
  • n个数,都是0或1代表该时间是否清醒,1清醒,0不清醒
输出

可以获得的最大分值

解题思路

利用滑动窗口的方式计算最大值,窗口大小为k,一开始在窗口中为数组前k个数,窗口开始向后移动,此时如果左边出窗口的分值对应清醒位置为0则要剪去这个分数。

代码
//主函数负责输入输出
public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNext()) {
            int len = in.nextInt();
            int wake = in.nextInt();
            int[] score = new int[len], wakeTime = new int[len];
            for(int i = 0;i < len;i++){
                score[i] = in.nextInt();
            }
            for(int i = 0;i < len;i++){
                wakeTime[i] = in.nextInt();
            }
            System.out.println(solve(wake,score,wakeTime));
        }
        in.nextInt();
    }

    private static int solve(int wake, int[] score, int[] wakeTime) {
        int max = 0;
        int i = 0;
        //初始前k个分值在窗口中
        for(;i < wake && i < score.length;i++){
            max += score[i];
        }
        int tmp = max;
        //其实这里循环到score.length - k即可,即最后一个分值进入窗口
        for(;i < score.length;i++){
            //如果左边出窗口元素对应位置为0要减去这个分值
            if(wakeTime[i - wake] == 0){
                tmp -= score[i - wake];
            }
            //当前进入位置本身为1,说明不管在不在窗口都要加上
            //这里max是当前最大值,而tmp是窗口当前情况最大值
            if(wakeTime[i] == 1){
                max += score[i];
            }

            tmp += score[i];
            max = Math.max(tmp ,max);
        }
        return max;
    }
}

收货题目

题目描述

地上有n堆苹果,每堆ai个,求第q个苹果属于第几堆

输入
  • 第一行n代表有n堆
  • n个数ai代表第i堆有几个苹果
  • m代表询问m次
  • m个qi代表每次询问是第qi个苹果
输出

m行,每行代表qi询问的答案

解题思路

首先计算出到当前堆为止一共有几个苹果,如输入为[1,3,5,7],则到当前堆的苹果数为1,4,9,16,那么第qi个苹果如果小于等于a0则属于第一堆,大于a0小于等于a1在第二堆,依次类推。很明显可以用二分查找来搜索答案。如果用java可以用Arrays.binarySearch()方法,函数在找到时会返回找到元素的位置,不存在时会返回一个负数,它的绝对值代表第一个大于它的数在第几个位置,例如对于上面例子数组a,binarySearch(a,3)返回-2,代表第一个大于它的是在第二个位置,即下标1。

代码
public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while(in.hasNext()){
            int n = in.nextInt();
            int[] arr = new int[n];
            for(int i = 0;i < n;i++){
                arr[i] = in.nextInt();
                //计算当前位置一共有几个苹果
                if(i>0){
                    arr[i] += arr[i-1];
                }
            }
            int m = in.nextInt();
            for (int i = 0;i < m;i++){
                System.out.println(solve(arr, in.nextInt()));
            }
        }
        in.close();
    }

    private static int solve(int[] arr, int pos) {
        int ans = Arrays.binarySearch(arr,pos);
        return ans >= 0 ? ans + 1 : Math.abs(ans);
    }

    //为了理解自己写一个binarySearch的类似实现,这里不存在直接返回第一个大于他的元素的位置
    private static int binarSeach(int[] arr,int val){
        int left = 0, right = arr.length - 1;
        while (left < right){
            int mid = left + (right - left >> 1);
            if(arr[mid] == val)
                return mid;
            if(arr[mid] < val)
                left = mid + 1;
            else
                right = mid;
        }
        return left;
    }

字典

题目描述

输入整形n,m代表这个字典里有n个’a’,m个’z’,他们所有的排列组合按字典顺序排序,求第k个字符串。

输入

n,m,k分别代表n个’a’,m个’z’,求字典第k个字符串

输出

第k个字符串,如n = 2,m = 2,k = 6输出”zzaa”

因为n = 2, m = 2,在字典有
aazz, azaz, azza, zaaz, zaza, zzaa

解题思路

这题的第一反应就是做一个带有重复元素的字符数组的全排列,然后按字典排序,或者直接将每次全排列的结果加入优先权队列或者TreeSet都可以。然而全排列时间复杂度为O(n!)输入m和n为0-100明显会超时,其实在n+m>22左右就开始超时了。所以这题应该是用dp算法来解决。

我们设dp[n][m]代表n个’a’,m个’z’有dp[n][m]个排列组合的数量,很明显dp[n][m]所有情况可以由两种方式得到,dp[n][m-1]代表n个’a’,m-1个’z’,由它的所有情况前面加一个’z’得到,还有dp[n-1][m]的所有情况前面加’a’得到(其实这个’a’或’z’加最前最后中间都行,但是一定要所有情况加在同一位置,并且加在最前面好理解这个算法)。这样我们可以得到公式如下

dp[n][m] = dp[n][m-1] + dp[n-1][m]

那么如何通过dp[n][m]得到第k个的字符串呢?首先明显的是k > dp[n][m]肯定不存在返回-1。那么当k <= dp[n][m]时,按字典顺序肯定先走a在前的所以先看dp[n-1]m如果k小于它说明肯定是前面加a,反之如果比dp[n-1][m]大,说明它在dp[n][m-1]中,前面要加z,并且它是dp[n][m-1]中的第k-dp[n-1][m]个(a开头的消耗了dp[n-1][m]个),那么直到寻找到dp的边界,剩下的’a’和’z’按照先’a’的原则追加到末尾

代码
public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNext()){
            int n = in.nextInt();
            int m = in.nextInt();
            int k = in.nextInt();
            System.out.println(solve(n, m, k));
        }
        in.close();
    }

private static String solve(int n, int m, int k){
        int[][] dp = new int[n+1][m+1];
        initDp(dp);
        if(k > dp[n][m])
            return "-1";
        int i = n, j = m;
        StringBuilder sb = new StringBuilder();
        while(i >0 && j > 0){
            int addA = dp[i-1][j], addZ = dp[i][j-1];
            if(addA >= k){//属于前dp[i-1][j]个追加'a'
                sb.append('a');
                i--;//因为是从dp[i-1][j]来的所以下一次对dp[i-1][j]继续搜索
                n--;//消耗了一个'a','a'剩余数量减1
            }else {
                sb.append('z');
                j--;
                m--;
                k = k - addA;
            }
        }
        while (n > 0) {
            sb.append('a');
            n--;
        }
        while (m > 0) {
            sb.append('z');
            m--;
        }
        return sb.toString();
    }

    //初始化dp
    private static void initDp(int[][] dp){
        int n = dp.length, m = dp[0].length;
        for(int i = 0;i < m;i++){
            dp[0][i] = 1;
        }
        for(int j = 0;j < n;j++){
            dp[j][0] = 1;
        }
        for(int i = 1;i < n;i++){
            for(int j = 1;j < m;j++){
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值