LeetCode-第一个星期

前言

最近一直在重温算法,该看的都看了一遍,今天开始准备刷题了每天一道,并不会把所有的题目都记录下来,会挑一些有趣的题目放在上面,欢迎一起讨论(第一天略微会简单点)。

二叉树的所有路径

LeetCode第257题,难度简单,该题需要输出二叉树从根节点到叶子节点的所有路径。
在这里插入图片描述
该题使用的是迭代的方式进行解答的,执行用时1ms,使用String进行根节点的一个叠加,这里还有一种想法:String在不断的叠加时,会耗费大量空间,可以使用Stack加StringBuilder的方式来节省空间。不断的迭代非叶子节点的左右节点,进行叠加,直到叶子节点,将其加入集合。

public class Solution1 {
    public static void main(String[] args) {
        Node root = new Node(1);
        Node node1 = new Node(2);
        Node node2 = new Node(3);
        Node node3 = new Node(4);
        Node node4 = new Node(5);
        Node node5 = new Node(6);
        Node node6 = new Node(7);
        Node node7 = new Node(8);
        Node node8 = new Node(9);


        root.left = node1;
        node1.left = node2;
        node1.right = node3;
        root.right = node4;
        node2.left = node5;
        node2.right = node6;
        node5.left = node7;
        node7.left = node8;
        //结果:[1->2->3->6->8->9, 1->2->3->7, 1->2->4, 1->5]
        System.out.println(binaryTreePaths(root));
    }

    public static List<String> binaryTreePaths(Node root) {
        List<String> result = new ArrayList<>();
        if (root == null) {
            return result;
        }
        findPath(root, root.val + "", result);
        return result;
    }

    private static void findPath(Node root, String string, List<String> result) {
        if (root.left == null && root.right == null) {
            result.add(string);
            return;
        }else{
            if (root.left != null) {
                findPath(root.left, string + "->" + root.left.val, result);
            }
            if (root.right != null) {
                findPath(root.right, string + "->" + root.right.val, result);
            }
        }
    }
}

class Node {
    int val;
    Node left;
    Node right;

    Node(int x) {
        val = x;
    }
}

IPO

LeetCode第502题,难度困难,从给定项目中选择最多 k 个不同项目的列表,以最大化最终资本,并输出最终可获得的最多资本。
在这里插入图片描述
该题思路首先需要将利润和成本组成一个对象,然后判断该项目中,那些是大于初始成本的,那些是小于初始成本的,小于初始成本的项目放入利润降序排列的队列,大于初始成本的项目放入成本升序排列的队列中,之后遍历利润队列,取出的第一个利润,肯定是利润最大的项目,当该项目的利润加到初始成本中后,再次判断成本队列中,是否有满足初始成本的项目,将其加入利润队列中,循环遍历得出最大利润。

 /**
     * 返回最大的资本
     *
     * @param k
     * @param W
     * @param Profits
     * @param Capital
     * @return
     */
    public static int findMaximizedCapital(int k, int W, int[] Profits, int[] Capital) {
        //创建两个优先队列
        PriorityQueue<Project> profitsQueue = new PriorityQueue<>(new ProfitsComparator());
        PriorityQueue<Project> capitalQueue = new PriorityQueue<>(new CapitalComparator());
        for (int i = 0; i < Profits.length; i++) {
            //将利润和所需资本绑定在一个对象中
            Project project = new Project(Profits[i], Capital[i]);
            //如果该项目所需的成本大于初始成本
            if (project.capital > W) {
                capitalQueue.add(project);
            } else {
                profitsQueue.add(project);
            }
        }
        while (k > 0 && !profitsQueue.isEmpty()) {
            //profitsQueue头部的是利润最大且满足初始成本的项目
            W += profitsQueue.poll().profits;
            //增加了初始成本后,判断capitalQueue的队头元素是否可以满足当前资本了
            while (!capitalQueue.isEmpty() && W >= capitalQueue.peek().capital) {
                //将其加入profitsQueue
                profitsQueue.add(capitalQueue.poll());
            }
            k--;
        }
        return W;
    }

    public static class Project {
        public int profits;
        public int capital;

        public Project(int profits, int capital) {
            this.profits = profits;
            this.capital = capital;
        }
    }

    /**
     * 以利润倒序
     */
    public static class ProfitsComparator implements Comparator<Project> {
        @Override
        public int compare(Project o1, Project o2) {
            return o2.profits - o1.profits;
        }
    }

    /**
     * 以成本升序
     */
    public static class CapitalComparator implements Comparator<Project> {
        @Override
        public int compare(Project o1, Project o2) {
            return o1.capital - o2.capital;
        }
    }

图像重叠

LeetCode835题,转换其中一个图像,向左,右,上,或下滑动任何数量的单位,并把它放在另一个图像的上面,怎样移动元素,可以得到最大的重叠数。
在这里插入图片描述
思路分析:其实该题的描述的过于复杂,转换一下,其实是求数组A中的元素1和数组B中的元素1,怎样的移动可以求出最大的重叠数,即将数组A中的元素1到数组B中的元素1的下标差求出来,并且不断的累加,得出结果。

public static int largestOverlap(int[][] A, int[][] B) {
        int max = 0;
        //存储A中元素1到B中元素1的重叠数
        int[][] nums = new int[2 * B.length][2 * B.length];
        for (int i = 0; i < A.length; i++) {
            for (int j = 0; j < A[i].length; j++) {
                //找到数组A中元素为1的坐标
                if (A[i][j] == 1) {
                    for (int k = 0; k < B.length; k++) {
                        for (int l = 0; l < B[i].length; l++) {
                            //寻找数组B中元素1的坐标
                            if (B[k][l] == 1) {
                                //使用固定的算法计算A、B元素的距离
                                nums[B.length - 1 + (k - i)][B.length - 1 + (l - j)]++;
                            }
                        }
                    }
                }
            }
        }
        //得出nums数组中最大的值,即为重叠数的最大值
        for (int i = 0; i < nums.length; i++) {
            for (int j = 0; j < nums[i].length; j++) {
                if (nums[i][j] > max) {
                    max = nums[i][j];
                }
            }
        }
        return max;
    }

递增的三元子序列

LeetCode334题,给定一个未排序的数组,判断这个数组中是否存在长度为 3 的递增子序列,可以不用连续,只是需要递增的3个数即可。
在这里插入图片描述
思路分析:该题只判断数组中的元素,是否存在三个递增的元素即可,并不要求连续,我们只需要记录第一个值和第二个值即可,第三个值如果同时大于前两个值,则说明存在三个递增的元素,返回true即可,同理遍历完数组后,未找到的话,则返回false。

    public static boolean increasingTriplet(int[] nums) {
        int one = Integer.MAX_VALUE;
        int two = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i++) {
           //如果小于第一个数,则将其记录下来
            if (one >= nums[i]) {
                one = nums[i];
            } else if (two >= nums[i]) {
                //不满足上面的判断,则说明是大于one的,且小于two的
                two = nums[i];
            } else {
                //如果都不满足,则说明该数是大于one和two的
                return true;
            }
        }
        return false;
    }

找出井字棋的获胜者

LeetCode1275题,黑白棋子谁先连成三个棋子谁先获胜,五子棋的简略版三子棋。
在这里插入图片描述
思路分析:该题只需判断moves数组中的最后一步即可,因为一旦获胜游戏就结束,所以只需围绕moves中的最后一步来展开判断即可。

       //步数小于5,不会有获胜者
        if (moves.length < 5) {
            return "Pending";
        }
        //记录对角线、行、列相同棋子出现的次数
        int rowCount = 0;
        int colCount = 0;
        int subCount = 0;
        int addCount = 0;
        //最后一步棋下标为moves.length-1,只需从上一步判断即可,循环也只需循环获胜者的步法
        for (int i = moves.length - 3; i >= 0; i-=2) {
            if (moves[moves.length - 1][0] == moves[i][0]) {
                colCount++;
                if (colCount == 2) {
                    return moves.length % 2 == 0 ? "B" : "A";
                }
            }
            if (moves[moves.length - 1][1] == moves[i][1]) {
                rowCount++;
                if (rowCount == 2) {
                    return moves.length % 2 == 0 ? "B" : "A";
                }
            }
            if (moves[moves.length - 1][0] + moves[moves.length - 1][1] == moves[i][0] + moves[i][1]) {
                addCount++;
                if (addCount == 2) {
                    return moves.length % 2 == 0 ? "B" : "A";
                }
            }
            if (moves[moves.length - 1][0] - moves[moves.length - 1][1] == moves[i][0] - moves[i][1]) {
                subCount++;
                if (subCount == 2) {
                    return moves.length % 2 == 0 ? "B" : "A";
                }
            }
        }

        if (moves.length == 9) {
            return "Draw";
        }
        return "Pending";

任务调度器

LeetCode621题,该题需要完成指定任务数组中的所有任务,并且有对应的规则,需要注意的是获取完成任务的最小时间。
在这里插入图片描述
思路分析:引用LeetCode官方和评论区一些见解,首先统计出现次数最多的一个种类,并且计算完成该种类需要的一个时间,在执行该种类任务的时候,产生的空闲时间对于其余任务来说,会有两种情况,一是足够完成剩余的所有任务,二是不够完成剩余的任务,如果是第一种情况,则返回完成种类任务次数最多的时间即可。如果是第二种情况的话,则说明Figure2图片中的格子个数不够用了,而需要增加的格子个数就是剩余任务的个数,则返回任务的长度即可。
在这里插入图片描述

       // 假设数组 ["A","A","A","B","B","C"],n = 2,A的频率最高,记为count = 3,所以两个A之间必须间隔2个任务,才能满足题意并且是最短
        // 时间(两个A的间隔大于2的总时间必然不是最短),因此执行顺序为: A->X->X->A->X->X->A,这里的X表示除了A以外其他字母,或者是待命,
        // 不用关心具体是什么,反正用来填充两个A的间隔的。上面执行顺序的规律是: 有count - 1个A,其中每个A需要搭配n个X,再加上最后一个A,
        // 所以总时间为 (count - 1) * (n + 1) + 1要注意可能会出现多个频率相同且都是最高的任务,比如 ["A","A","A","B","B","B","C","C"],
        // 所以最后会剩下一个A和一个B,因此最后要加上频率最高的不同任务的个数 maxCount公式算出的值可能会比数组的长度小,
        // 如["A","A","B","B"],n = 0,此时要取数组的长度
        if (tasks.length <= 1 || n < 1) return tasks.length;
        //步骤1
        int[] counts = new int[26];
        for (int i = 0; i < tasks.length; i++) {
            counts[tasks[i] - 'A']++;
        }
        //步骤2
        Arrays.sort(counts);
        int maxCount = counts[25];
        int retCount = (maxCount - 1) * (n + 1) + 1;
        int i = 24;
        //步骤3
        while (i >= 0 && counts[i] == maxCount) {
            retCount++;
            i--;
        }
        //步骤4
        return Math.max(retCount, tasks.length);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值