美文网首页囧囧算法
08-平面最大点集合-最小数*区间所有数和-PMandIdea

08-平面最大点集合-最小数*区间所有数和-PMandIdea

作者: 囧么肥事 | 来源:发表于2019-08-16 15:47 被阅读0次

年轻即出发...

简书https://www.jianshu.com/u/7110a2ba6f9e

知乎https://www.zhihu.com/people/zqtao23/posts

GitHub源码https://github.com/zqtao2332

个人网站http://www.zqtaotao.cn/ (停止维护更新内容)

QQ交流群:606939954

​ 咆哮怪兽一枚...嗷嗷嗷...趁你现在还有时间,尽你自己最大的努力。努力做成你最想做的那件事,成为你最想成为的那种人,过着你最想过的那种生活。也许我们始终都只是一个小人物,但这并不妨碍我们选择用什么样的方式活下去,这个世界永远比你想的要更精彩。

最后:喜欢编程,对生活充满激情



本节内容预告

实例1:平面最大点集合

实例2:最小数*区间所有数和

实例3:PMandIdea



实例1:平面最大点集合

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

1_1_点集分布.png

请实现代码找到集合P中的所有”最大“点的集合并输出。输入第一行输入点集的个数N, 接下来N行,每行两个数字代表点的x轴和Y轴。输出输出“最大的” 点集合, 按照 轴从小到大的方式输出,每行两个数字分别代表点的x轴和Y轴。

样例输入

5

1 2

5 3

4 6

7 5

9 0

输出结果按照 x 轴排序

4 6

7 5

9 0

按照x从小到大排序,然后从后向前进行遍历

扩展:x y 可以重复,即边界点不算在右上角
同理先按照x 从小到大排序,再按照y 大到小排序,然后向前进行遍历
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Scanner;

public class Code_25_RightCorner {

    public static class Node {
        int x;
        int y;

        public Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    // 暴力
    public static LinkedList<Node> getRightCornerNodes1(Node[] nodes) {

        if (nodes == null || nodes.length == 0) return null;

        Arrays.sort(nodes, new Comparator<Node>() {
            @Override
            public int compare(Node o1, Node o2) {
                return o1.x - o2.x;
            }
        });

        LinkedList<Node> res = new LinkedList<>();

        int index = 0;
        for (int i = 0; i < nodes.length; i++) {
            Node a = nodes[i];
            boolean flag = true;
            for (int j = 0; j < nodes.length; j++) {
                Node b = nodes[j];
                if (b.x > a.x && b.y > a.y) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                res.add(a);
            }
        }
        return res;
    }

    // O(N)
    public static LinkedList<Node> getRightCornerNodes2(Node[] nodes) {
        LinkedList<Node> res = new LinkedList<>();

        Arrays.sort(nodes, new Comparator<Node>() {
            @Override
            public int compare(Node o1, Node o2) {
                return o1.x - o2.x;
            }
        });

        res.add(nodes[nodes.length - 1]); // 最后一个点,一定满足

        int rightMaxY = nodes[nodes.length - 1].y; // 记录最高 y

        // 从右往左遍历,只要是小于maxY 的一定都不满足
        for (int i = nodes.length - 2; i >= 0; i--) {
            Node node = nodes[i];
            if (rightMaxY < node.y) {
                res.addFirst(node);
            }
            rightMaxY = Math.max(rightMaxY, nodes[i].y);
        }

        return res;
    }

    // O(N) 扩展,点的x , y 可以相同
    public static LinkedList<Node> getRightCornerNodes3(Node[] nodes) {
        LinkedList<Node> res = new LinkedList<>();

        Arrays.sort(nodes, new Comparator<Node>() {
            @Override
            public int compare(Node o1, Node o2) {
                if (o1.x != o2.x) {
                    return o1.x - o2.x; // x -> 小到大
                } else {
                    return o2.y - o1.y; // y -> 大到小
                }
            }
        });

        res.addFirst(nodes[nodes.length - 1]);
        int rightMaxY = nodes[nodes.length - 1].y;
        for (int i = nodes.length - 2; i >=0; i--) {
            if (nodes[i].y >= rightMaxY) {
                res.addFirst(nodes[i]);
            }
            rightMaxY = Math.max(rightMaxY, nodes[i].y);
        }
        return res;
    }

    public static void printLinkedList(LinkedList<Node> list) {
        for (Node node : list) {
            System.out.print("(" + node.x + "," + node.y + ") ");
        }
        System.out.println();
    }

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

        while (in.hasNext()) {
            int N = in.nextInt();

            Node[] nodes = new Node[N];
            for (int i = 0; i < N; i++) {
                nodes[i] = new Node(in.nextInt(), in.nextInt());
            }

            printLinkedList(getRightCornerNodes1(nodes));
            printLinkedList(getRightCornerNodes2(nodes));
            printLinkedList(getRightCornerNodes3(nodes));
        }
    }
}

实例2:最小数区间所有数和*

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

区间中的最小数*****区间所有数的和最后程序

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

[6] =6* 6=36;

[2] =2*2=4 ;

[1] =11=1;

[6,2] =2 8= 16;

[2,1] =13=3;

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

从上述计算可见选定区间[6] ,计算值为36,则程序输出为36区间内的所有数字都在[0, 100]的范围内;

单调栈:递减栈,快速找到一个元素两边最近比它大的数
import java.util.Stack;

public class Code_26_AllTimesMinToMax {

    // 暴力
    public static int max1(int[] arr) {
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < arr.length; i++) { // 0~N-1
            for (int j = i; j < arr.length; j++) { // i~N-1
                int minNum = Integer.MAX_VALUE;
                int sum = 0;

                for (int k = i; k <= j; k++) { // i~j 之间子数组
                    sum += arr[k];
                    minNum = Math.min(minNum, arr[k]);
                }
                max = Math.max(max, minNum * sum);
            }
        }
        return max;
    }

    // 单调栈
    public static int max2(int[] arr) {
        int size = arr.length;
        int[] sums = new int[size]; // 预处理数组
        sums[0] = arr[0];
        for (int i = 1; i < size; i++) {
            sums[i] = sums[i - 1] + arr[i];// 计算arr数组每一项和
            // 6 2 8
            // 6 8 16
        }
        int max = Integer.MIN_VALUE;
        Stack<Integer> stack = new Stack<>(); // 单调栈:递减栈,快速找到一个元素两边最近比它大的数
        // 这里单调栈存放下标

        for (int i = 0; i < size; i++) {
            while (!stack.isEmpty() && arr[stack.peek()] >= arr[i]) {
                int j = stack.pop(); // 当前区间最小
                max = Math.max(max,
                        (stack.isEmpty() ? sums[i - 1] : (sums[i - 1] - sums[stack.peek()]))
                                * arr[j]);
            }
            stack.push(i);
        }
        while (!stack.isEmpty()) { // 余栈处理
            int j = stack.pop();
            max = Math.max(max, (stack.isEmpty() ? sums[size - 1]
                    : (sums[size - 1] - sums[stack.peek()])) * arr[j]);
        }
        return max;
    }

    public static int[] gerenareRondomArray() {
        int[] arr = new int[(int) (Math.random() * 20) + 10];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * 101);
        }
        return arr;
    }

    public static void main(String[] args) {
        int testTimes = 2000000;
        for (int i = 0; i < testTimes; i++) {
            int[] arr = gerenareRondomArray();
            if (max1(arr) != max2(arr)) {
                System.out.println("FUCK!");
                break;
            }
        }

    }

}

实例3:PMandIdea

产品经理(PM)有很多好的idea,而这些idea需要程序员实现。现在有N个PM,在某个时间会想出一个 idea,每个idea有提出时间、所需时间和优先等级。对于一个PM来说,最想实现的 idea首先考虑优先等级高的,相同的情况下优先所需时间最小的,还相同的情况下选择最早想出的,没有PM会在同一时刻提出两个idea同时有M个程序员,每个程序员空闲的时候就会查看每个PM尚未执行并且最想完成的一个idea,然后从中挑选出所需时间最小的一个idea独立实现,如果所需时间相同则选择PM序号最小的。直到完成了idea才会重复上述操作。如果有多个同时处于空闲状态的程序员,那么他们会依次进行查看idea的操作。求每个idea实现的时间。

输入

输入第一行三个数N、M、P,分别表示有N个PM, M个程序员, P个idea。随后有P行,每行有4个数字,分别是PM序号、提出时间、优先等级和所需时间。所有输入数据范围为[1, 3000]

输出

输出P行,分别表示每个idea实现的时间点。

样例输入

2 2 5

1 1 1 2

1 2 1 1

1 3 2 2

2 1 1 2

2 3 5 5

样例输出

3

4

5

3

9

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;

/**
 * @description: SED: Software Develop Engineer
 * PM: Project Manager
 */
public class Code_27_SDEandPM {

    /**
     * 项目的数据结构
     * 封装项目的基本属性
     */
    public static class Program {
        public int index; // 项目编号
        public int pmId; // 归属于哪个 pm, pmId: Project Manager的ID
        public int startTime; // 项目可以开始做的时间,start之前的时间段不能做
        public int rank; // 项目的优先级
        public int costTime; // 项目花费时间

        public Program(int index, int pmId, int beginTime, int rank, int costTime) {
            this.index = index;
            this.pmId = pmId;
            this.startTime = beginTime;
            this.rank = rank;
            this.costTime = costTime;
        }
    }


    /**
     * 比较器
     * pm 拥有众多项目,按照比较器规则排序最喜欢的项目
     * <p>
     * 规则:
     * 1、优先级高
     * 2、花费时间短
     * 3、最先想出的
     */
    public static class PmLoveRule implements Comparator<Program> {
        @Override
        public int compare(Program o1, Program o2) {
            if (o1.rank != o2.rank) {
                return o1.rank - o2.rank;
            } else if (o1.costTime != o2.costTime) {
                return o1.costTime - o2.costTime;
            } else {
                return o1.startTime - o2.startTime;
            }
        }
    }


    /**
     * 大结构
     * 1、对于激活状态的项目program(startTime 在 程序员苏醒范围内),进入大结构
     * <p>
     * 2、对于这个program
     * 先经过pm 喜欢的规则进行排序,选出 PM 最想做的项目
     * 然后经过SDE 喜欢的规则进行排序,最后弹出是程序员最想做的项目
     * <p>
     * 3、这个大结构唯一暴露出去的只有两个接口,一个是add()  一个是pop()
     */
    public static class BigQueues {
        private List<PriorityQueue<Program>> pmQueues;// PM 组成的队列集合,每一个PM独立为一个堆
        private Program[] heap; // 存放每一个PM最想做的项目,排序规则按照SdeLoveRule, 选出程序员最想做的项目
        private int[] indexes;
        private int heapSize; // 大结构里项目个数

        public BigQueues(int size) { // size是PM 的个数
            this.heapSize = 0;
            this.heap = new Program[size]; // 每个PM都贡献一个自己最想要做的项目
            this.indexes = new int[size + 1];
            for (int i = 0; i <= size; i++) {
                indexes[i] = -1;
            }

            pmQueues = new ArrayList<>();
            for (int i = 0; i <= size; i++) { // size 个PM,每一个都独立一个堆
                pmQueues.add(new PriorityQueue<>(new PmLoveRule()));
            }
        }

        public boolean isEmpty() {
            return heapSize == 0;
        }


        // 新增一个项目进大结构
        public void add(Program program) {
            PriorityQueue<Program> queue = pmQueues.get(program.pmId);
            queue.add(program);

            // 大结构中新增元素后,heap可能会发生变化
            Program head = queue.peek();
            int heapindex = indexes[head.pmId];
            if (heapindex == -1) {
                heap[heapSize] = head;
                indexes[head.pmId] = heapSize;
                heapInsert(heapSize++);
            } else {
                heap[heapindex] = head;
                heapInsert(heapindex);
            }
        }


        private void heapInsert(int index) {
            while (index != 0) {
                int parent = (index - 1) / 2;
                if (sdeLoveRule(heap[parent], heap[index]) > 0) {
                    swap(parent, index);
                    index = parent;
                } else {
                    break;
                }
            }
        }


        private void swap(int index1, int index2) {
            Program p1 = heap[index1];
            Program p2 = heap[index2];
            heap[index1] = p2;
            heap[index2] = p1;
            indexes[p1.pmId] = index2;
            indexes[p2.pmId] = index1;
        }


        // SDE 排序规则
        private static int sdeLoveRule(Program o1, Program o2) {
            if (o1.costTime != o2.costTime) {
                return o1.costTime - o2.costTime;
            } else {
                return o1.pmId - o2.pmId;
            }
        }


        public Program pop() {
            Program head = heap[0];
            PriorityQueue<Program> queue = pmQueues.get(head.pmId);
            queue.poll();
            if (queue.isEmpty()) {
                swap(0, heapSize - 1);
                heap[--heapSize] = null;
                indexes[head.pmId] = -1;
            } else {
                heap[0] = queue.peek();
            }
            heapify(0);
            return head;
        }

        private void heapify(int index) {
            int left = index * 2 + 1;
            int right = index * 2 + 2;
            int best = index;
            while (left < heapSize) {
                if (sdeLoveRule(heap[left], heap[index]) < 0) {
                    best = left;
                }
                if (right < heapSize && sdeLoveRule(heap[right], heap[best]) < 0) {
                    best = right;
                }
                if (best == index) {
                    break;
                }
                swap(best, index);
                index = best;
                left = index * 2 + 1;
                right = index * 2 + 2;
            }
        }

    }

    public static class StartRule implements Comparator<Program> {

        @Override
        public int compare(Program o1, Program o2) {
            return o1.startTime - o2.startTime;
        }

    }

    public static int[] workFinish(int pms, int sdes, int[][] programs) {
        PriorityQueue<Program> programsQueue = new PriorityQueue<>(new StartRule());
        for (int i = 0; i < programs.length; i++) {
            Program program = new Program(i, programs[i][0], programs[i][1], programs[i][2], programs[i][3]);
            programsQueue.add(program);
        }
        PriorityQueue<Integer> sdeWakeQueue = new PriorityQueue<>();
        for (int i = 0; i < sdes; i++) {
            sdeWakeQueue.add(1);
        }
        BigQueues bigQueues = new BigQueues(pms);
        int finish = 0;
        int[] ans = new int[programs.length];
        while (finish != ans.length) {
            int sdeWakeTime = sdeWakeQueue.poll();
            while (!programsQueue.isEmpty()) {
                if (programsQueue.peek().startTime > sdeWakeTime) {
                    break;
                }
                bigQueues.add(programsQueue.poll());
            }
            if (bigQueues.isEmpty()) {
                sdeWakeQueue.add(programsQueue.peek().startTime);
            } else {
                Program program = bigQueues.pop();
                ans[program.index] = sdeWakeTime + program.costTime;
                sdeWakeQueue.add(ans[program.index]);
                finish++;
            }
        }
        return ans;
    }

    public static void printArray(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

    public static void main(String[] args) {
        int pms = 2;
        int sde = 2;
        int[][] programs = {{1, 1, 1, 2}, {1, 2, 1, 1}, {1, 3, 2, 2}, {2, 1, 1, 2}, {2, 3, 5, 5}};
        int[] ans = workFinish(pms, sde, programs);
        printArray(ans);
    }
}

相关文章

  • 08-平面最大点集合-最小数*区间所有数和-PMandIdea

    年轻即出发... 简书:https://www.jianshu.com/u/7110a2ba6f9e 知乎:htt...

  • [day8] [LeetCode] [title435,5]

    435. 无重叠区间 给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 注意: 可以认为区间的...

  • T435、无重叠区间

    给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。注意:可以认为区间的终点总是大于它的起点。区间...

  • Leetcode 精选之贪心思想( 无重叠区间)

    题目描述 给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 注意: 可以认为区间的终点总是大于...

  • 贪婪算法

    贪婪算法:选择局部最优解达到全局最优 区间调度问题 给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不...

  • 435. 无重叠区间

    给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。 注意: 可以认为区间的终点总是大于它的起点。...

  • 排列307

    百合数04689/小数04 十质数和大区间/1235789/大区间789 个小区间012/质数12 小复式04/7...

  • Fenwick Tree/B.I.T树状数组算法

    树状数组适用范围:给定区间,求最值,求和,区间单点修改。与RMQ不同的是,RMQ一般只用作区间求最值。但在最值方面...

  • 区间---RMQ区间最值查询

    RMQ区间最值查询,对于长度为n的数组A[]。RMQ(i,j),返回数组A区间[i , j]内的最大值或最小值。 ...

  • 最值

    WIKI 1 利用导数求函数在闭区间上的最值 利用导数求函数在开区间的最值 应用

网友评论

    本文标题:08-平面最大点集合-最小数*区间所有数和-PMandIdea

    本文链接:https://www.haomeiwen.com/subject/wxkqsctx.html