字节2018校招笔试

文章介绍了在给定二维点集中寻找最大点的方法,采用贪心策略和单调队列优化,以及如何通过计算区间和找到数组序列的最大值。
摘要由CSDN通过智能技术生成

P01

1.题目:

编程题1

P为给定的二维平面整数点集。定义 P 中某点x,如果x满足 P 中任意点都不在 x 的右上方区域内(横纵坐标都大于x),则称其为“最大的”。求出所有“最大的”点的集合。(所有点的横坐标和纵坐标都不重复, 坐标轴范围在[0, 1e9) 内)

如下图:实心点为满足条件的点的集合。请实现代码找到集合 P 中的所有 ”最大“ 点的集合并输出。

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 32M,其他语言64M

输入描述:

第一行输入点集的个数 N, 接下来 N 行,每行两个数字代表点的 X 轴和 Y 轴。
对于 50%的数据,  1 <= N <= 10000;
对于 100%的数据, 1 <= N <= 500000;

输出描述:

输出“最大的” 点集合, 按照 X 轴从小到大的方式输出,每行两个数字分别代表点的 X 轴和 Y轴。

示例1

输入例子:

5
1 2
5 3
4 6
7 5
9 0

输出例子:

4 6
7 5
9 0

2.思路:

首先按照数据量 C语言的1s对应常数级10^8,所以双层for循环O(n^2)可以通过50%的数据。

后来考虑凸包,但是只学到向外围一圈,这个方法需要再学习一下

最后考虑贪心解法,按x或y逆序,此时如果比前面的y或x大即可,画图思考一下即可,若按y逆序直接输出结果即可,但通过率只有60%,按x逆序不借用系统数据结构实现,通过率可达到70%,未想到更好的解法,看到讨论C的用户可以用scanf等方式缩短读取数据时间可过,Java未想到更好的办法。

3.代码

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = Integer.parseInt(sc.nextLine());
        int[][] star = new int[N][2];
        int index = 0;
        while(N-- > 0){
            int a = sc.nextInt();
            int b = sc.nextInt();
            star[index][0] = a;
            star[index++][1] = b; 
        }
        Arrays.sort(star,(a,b) ->{
            return  b[0] - a[0];
        });
        int maxY = -1;
        int[] res = new int[500000];
        int size = 0;
        for(int i = 0;i < star.length;i++){
           if(star[i][1] > maxY){
           res[size++] = i;
            maxY = star[i][1];
           }
        }
        for(int i = size - 1;i >= 0;i--){
            System.out.println(star[res[i]][0] + " " + star[res[i]][1]);
        }
    }
}

P02

1.题目

2.

编程题2

给定一个数组序列, 需要求选出一个区间, 使得该区间是所有区间中经过如下计算的值最大的一个:

区间中的最小数 * 区间所有数的和最后程序输出经过计算后的最大值即可,不需要输出具体的区间。如给定序列  [6 2 1]则根据上述公式, 可得到所有可以选定各个区间的计算值:

[6] = 6 * 6 = 36;

[2] = 2 * 2 = 4;

[1] = 1 * 1 = 1;

[6,2] = 2 * 8 = 16;

[2,1] = 1 * 3 = 3;

[6, 2, 1] = 1 * 9 = 9;

从上述计算可见选定区间 [6] ,计算值为 36, 则程序输出为 36。

区间内的所有数字都在[0, 100]的范围内;

时间限制:C/C++ 3秒,其他语言6秒

空间限制:C/C++ 128M,其他语言256M

输入描述:

第一行输入数组序列长度n,第二行输入数组序列。
对于 50%的数据,  1 <= n <= 10000;
对于 100%的数据, 1 <= n <= 500000;

输出描述:

输出数组经过计算后的最大值。

示例1

输入例子:

3
6 2 1

输出例子:

36

2.思路

1.首先区间最小值与区间和,先想到用线段树,区间最小值和区间和都是O(logn),但是区间和明显使用前缀和计算更快一些,因为不涉及修改操作。但是需要遍历每个区间,时间复杂度为O((n^2)logn)根据数据量来看明显无法通过。

2.因为需要每个区间的最小值和sum,已知所有数都在[0,100],所以能想到和具有单调性,能考虑到贪心解为最大值的平方 和 最小值 * 数组sum取max,但如果有0则无法通过

3.因为具有单调性,只需要确定区间内最小值即可,区间和可以使用前缀和解决,所以想到单调队列+前缀和解决方式,成功通过

3.代码

import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = Integer.parseInt(sc.nextLine());
        String[] s = sc.nextLine().split(" ");
        int[] arr = new int[n];
        int[] preSum = new int[n + 1];
        for (int i = 0; i < n; i++) {
            arr[i] = Integer.parseInt(s[i]);
            preSum[i + 1] = preSum[i] + arr[i];
        }
        int ans = 0;
        //[j + 1] - [i]
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < n; i++) {
            while (!stack.isEmpty() && arr[i] < arr[stack.peek()]) {
                int minIndex = stack.pop();
                int min = arr[minIndex];
                int l = !stack.isEmpty() ? stack.peek() : -1;
                l += 1;
                int r = i - 1;
                ans = Math.max(ans, (preSum[r + 1] - preSum[l]) * min);
            }
            stack.push(i);
        }
        while (!stack.isEmpty()) {
            int minIndex = stack.pop();
            int min = arr[minIndex];
            int l = !stack.isEmpty() ? stack.peek() : -1;
            l += 1;
            int r = n - 1;
            ans = Math.max(ans, (preSum[r + 1] - preSum[l]) * min);
        }
        System.out.println(ans);
    }
}

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值