hazy的leetcode刷题笔记(三)

leetcode.402:移掉K位数字
给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。
注意:
num 的长度小于 10002 且 ≥ k。
num 不会包含任何前导零。
示例 1 :
输入: num = “1432219”, k = 3
输出: “1219”
解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。
示例 2 :
输入: num = “10200”, k = 1
输出: “200”
解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
示例 3 :
输入: num = “10”, k = 2
输出: “0”
解释: 从原数字移除所有的数字,剩余为空就是0。

class Solution {
    public String removeKdigits(String num, int k) {
        /*基本思路:遍历字符串,如果后一个字符比前一个字符大 则保留,如果小,去掉前一个字符,并持续比较
        最终形成一个递增序列,再选择前n - k个数字即可
        */
        if(num.length() == k) return "0";
        LinkedList<Character> stack = new LinkedList<Character>();
        int number = num.length() - k;
        //形成递增序列
        for(int i = 0; i < num.length(); i++) {
            while(k > 0 && !stack.isEmpty() && (int)(stack.getLast() - num.charAt(i)) > 0) {
                stack.removeLast();
                k--;
            }
            stack.addLast(num.charAt(i));
        }
        StringBuilder result = new StringBuilder();
        //选择前n - k个
        for(char c : stack) {
            if(c == '0' && result.length() == 0) continue;
            if(number > 0) {
                result.append(c);
                number--;
            } 
            else break;
        }
        //如果没有返回值那么一定是0
        if(result.length() == 0) return "0";
        return result.toString();
        
    }
}

在这里插入图片描述

leetcode.316去除重复字母
leetcode.1081不同字符的最小子序列
两道题是一样的
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入:s = “bcabc”
输出:“abc”
示例 2:
输入:s = “cbacdcbc”
输出:“acdb”
提示:
1 <= s.length <= 104
s 由小写英文字母组成
本题的思路来源:
https://blog.csdn.net/azl397985856/article/details/107373699

class Solution {
    public String removeDuplicateLetters(String s) {
        /*基本思路:构造一个单调递增的序列
        遍历字符串时,只要字符不在栈中就添加到栈中,并且添加的过程中,如果前一个字符大于它,就把前一个字符从栈中去掉(除非这个字符剩下的次数为0)
        并且把字符剩下出现的次数减一 最终形成的栈就是结果
        */
        if(s.length() == 0 || s.length() == 1) return s;
        //栈
        LinkedList<Character> stack = new LinkedList<>();
        //记录字符剩下出现的次数
        Map<Character, Integer> number = new HashMap<>();
        //扫描字符出现的次数
        for(int i = 0; i < s.length(); i++) {
            number.put(s.charAt(i), number.getOrDefault(s.charAt(i), 0) + 1);
        }

        for(int i = 0; i < s.length(); i++) {
            //如果字符已在栈中就跳过
            if(!stack.contains(s.charAt(i))) {
                //如果前面的字符剩下次数大于0并且比当前的字符大,那就去掉
                while(!stack.isEmpty() && number.get(stack.getLast()) > 0 && (int)(s.charAt(i) - stack.getLast()) < 0) {
                    stack.removeLast();
                }
                //把当前字符添加到栈中
                stack.addLast(s.charAt(i));
            }
            //减少当前字符的次数
            number.put(s.charAt(i), number.get(s.charAt(i)) - 1);
        }
        //形成结果
        StringBuilder result = new StringBuilder();
        for(int i = 0; i < stack.size(); i++) {
                result.append(stack.get(i));
        }   
        return result.toString();
    }
}

在这里插入图片描述

leetcode.659:分割数组为连续子序列-每日一题
给你一个按升序排序的整数数组 num(可能包含重复数字),请你将它们分割成一个或多个子序列,其中每个子序列都由连续整数组成且长度至少为 3 。
如果可以完成上述分割,则返回 true ;否则,返回 false 。
示例 1:
输入: [1,2,3,3,4,5]
输出: True
解释:
你可以分割出这样两个连续子序列 :
1, 2, 3
3, 4, 5
示例 2:
输入: [1,2,3,3,4,4,5,5]
输出: True
解释:
你可以分割出这样两个连续子序列 :
1, 2, 3, 4, 5
3, 4, 5
示例 3:
输入: [1,2,3,4,4,5]
输出: False
提示:
输入的数组长度范围为 [1, 10000]

class Solution {
    public boolean isPossible(int[] nums) {
        /* 基本思路:一个哈希表存储数字出现的次数、一个哈希表存储以该数字结尾的子序列的个数
        遍历数字时,这个数字n有四种选择:1、添加到n-1的子序列中,前提是存在以n-1为结尾的序列
        2、另起一个序列,但是得保证n+1和n+2次数都大于0
        3、如果n的次数已经为0那么直接跳过它,因为它已经被用完了
        4、如果以上情况都不符合,说明无法形成子序列了,就直接返回false
        */

        //记录数字出现的次数
        Map<Integer, Integer> record = new HashMap<>();
        //记录以该数字结尾的子序列的个数
        Map<Integer, Integer> tail = new HashMap<>();
        //记录数字出现的次数
        for(int num :nums) record.put(num, record.getOrDefault(num, 0) + 1);

        for(int num : nums) {
            //如果该数字的次数为0了就继续下一个数字
            if(record.get(num) == 0) continue;
            //添加到上一个数字的子序列
            else if(record.get(num) > 0 && tail.getOrDefault(num - 1, 0) > 0) {
                record.put(num, record.getOrDefault(num, 0) - 1);
                tail.put(num - 1, tail.get(num - 1) - 1);
                tail.put(num, tail.getOrDefault(num, 0) + 1);
            }
            //另起一个新的序列
            else if(record.get(num) > 0 && record.getOrDefault(num + 1, 0) > 0 && record.getOrDefault(num + 2, 0) > 0) {
                record.put(num, record.getOrDefault(num, 0) - 1);
                record.put(num + 1, record.getOrDefault(num + 1, 0) - 1);
                record.put(num + 2, record.getOrDefault(num + 2, 0) - 1);
                tail.put(num + 2, tail.getOrDefault(num + 2, 0) + 1);
            }
            //都不符合直接返回
            else {
                return false;
            }
        }
        return true;
    }
}

在这里插入图片描述

leetcode.621:任务调度器-每日一题
给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表。其中每个字母表示一种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。在任何一个单位时间,CPU 可以完成一个任务,或者处于待命状态。
然而,两个 相同种类 的任务之间必须有长度为整数 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。
你需要计算完成所有任务所需要的 最短时间
示例 1:
输入:tasks = [“A”,“A”,“A”,“B”,“B”,“B”], n = 2
输出:8
解释:A -> B -> (待命) -> A -> B -> (待命) -> A -> B
在本示例中,两个相同类型任务之间必须间隔长度为 n = 2 的冷却时间,而执行一个任务只需要一个单位时间,所以中间出现了(待命)状态。
示例 2:
输入:tasks = [“A”,“A”,“A”,“B”,“B”,“B”], n = 0
输出:6
解释:在这种情况下,任何大小为 6 的排列都可以满足要求,因为 n = 0
[“A”,“A”,“A”,“B”,“B”,“B”]
[“A”,“B”,“A”,“B”,“A”,“B”]
[“B”,“B”,“B”,“A”,“A”,“A”]

诸如此类

class Solution {
    public int leastInterval(char[] tasks, int n) {
        /*基本思路:一开始的想法和评论区的大佬比较相近,都是取最大频率先组成一个有间隔的数组
        再往里面插入其他。但是没他考虑那么全面。
        具体思路可以看评论区,思路很清晰
        */
        int[] record = new int[26];
        int nowMax = 0;
        int nowMaxIndex = 0;
        int maxCount = 0;
        Arrays.fill(record, 0);
        for(int i = 0; i < tasks.length; i++) {
            record[(int)(tasks[i] - 'A')]++;
        }
        for(int i = 0; i < 26; i++) {
            if(record[i] > nowMax) {
                nowMax = record[i];
                nowMaxIndex = i;
            };
        }
        for(int i = 0; i < 26; i++) {
            if(record[i] == nowMax) {
                maxCount++;
            };
        }
        return Math.max((nowMax - 1) * (n + 1) + maxCount, tasks.length);
    }
}

在这里插入图片描述

leetcode.118杨辉三角-每日一题
给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。
在这里插入图片描述

class Solution {
    public List<List<Integer>> generate(int numRows) {
        /*基本思路:就是最简单的取上一行的数字进行相加
        但是这道题给我的最大成果是知道了怎么从int[]转到List:
            Arrays.stream(fir).boxed().collect(Collectors.toList())
        */
        ArrayList<List<Integer>> result = new ArrayList<List<Integer>>();
        int[] fir = new int[]{1};
        int[] sec = new int[]{1, 1};
        if(numRows == 0) return result;
        result.add(Arrays.stream(fir).boxed().collect(Collectors.toList()));
        if(numRows == 1) return result;
        result.add(Arrays.stream(sec).boxed().collect(Collectors.toList()));

        for(int i = 3; i <= numRows; i++) {
            int[] temp = new int[i];
            temp[0] = 1;
            for(int j = 1; j <= i / 2; j++) {
                temp[j] = sec[j - 1] + sec[j]; 
            }
            for(int j = i / 2; j < i; j++) {
                temp[j] = temp[i - 1 - j];
            }
            result.add(Arrays.stream(temp).boxed().collect(Collectors.toList()));
            sec = temp;
        }
        return result;
    }
}

在这里插入图片描述

leetcode.141:环形链表-hot100
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?

public class Solution {
    public boolean hasCycle(ListNode head) {
        /*基本思路:快慢指针,一个一次移动一个节点,一个一次移动两个节点。
        如果有环,一定会相遇 
        快慢指针!好,又会了一种解题方法
        */
        ListNode slow = head;
        ListNode fast = head;

        while(fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast) return true;
        }
        return false;
    }
}

在这里插入图片描述

leetcode.861:翻转矩阵后的得分-每日一题
有一个二维矩阵 A 其中每个元素的值为 0 或 1 。
移动是指选择任一行或列,并转换该行或列中的每一个值:将所有 0 都更改为 1,将所有 1 都更改为 0。
在做出任意次数的移动后,将该矩阵的每一行都按照二进制数来解释,矩阵的得分就是这些数字的总和。
返回尽可能高的分数。
示例:
输入:[[0,0,1,1],[1,0,1,0],[1,1,0,0]]
输出:39
解释:
转换为 [[1,1,1,1],[1,0,0,1],[1,1,1,1]]
0b1111 + 0b1001 + 0b1111 = 15 + 9 + 15 = 39

class Solution {
    public int matrixScore(int[][] A) {
        /* 基本思路:要达到总体最大,那么除了要保证第一列全都是1以外,还要保证后面每一列的1的个数比0多
        所以先遍历每一行,把所有行的变成第一个数字为1
        接着按列去遍历,如果这列的1个数少于0,就翻转这一列
        */
        if(A.length == 1) return 1<<A[0].length - 1;
        int result = 0;
        //所有行的变成第一个数字为1
        for(int i = 0; i < A.length; i++) {
            if(A[i][0] == 0) {
                for(int j = 0; j < A[0].length; j++) {
                    if(A[i][j] == 0)
                        A[i][j] = 1;
                    else
                        A[i][j] = 0;
                }
            }
        }
        //按列遍历
        for(int i = 1; i < A[0].length; i++) {
            int count = 0;
            for(int j = 0; j < A.length; j++) {
                if(A[j][i] == 1) count++;
            }
            if(count <= A.length / 2) {
                for(int j = 0; j < A.length; j++) {
                    if(A[j][i] == 0)
                        A[j][i] = 1;
                    else
                        A[j][i] = 0;
                }
            }
        }
        //计算最后的结果
        for(int i = 0; i < A[0].length; i++) {
            int colSum = 0;
            for(int j = 0; j < A.length; j++) {
                if(A[j][i] == 1) colSum++;
            }
            result = result + colSum * (1<<(A[0].length - 1 - i)) ;
        }
        return result;
    }
}

在这里插入图片描述

这个错误是由于权限问题导致的。在操作系统中,每个文件和文件夹都有特定的权限设置,决定了谁可以对其进行读取、写入和执行操作。当你尝试访问一个文件或文件夹时,如果你没有足够的权限,就会出现"PermissionError: [Errno 13] Permission denied"错误。 解决这个问题的方法有几种: 1. 检查文件或文件夹的权限:首先,你可以检查文件或文件夹的权限设置,确保你有足够的权限来访问它们。你可以使用操作系统提供的命令或图形界面工具来查看和修改权限设置。 2. 以管理员身份运行程序:如果你是在Windows操作系统上运行程序,并且遇到了权限问题,你可以尝试以管理员身份运行程序。右键点击程序的可执行文件,选择"以管理员身份运行"选项。 3. 更改文件或文件夹的所有者:如果你是在Linux或Mac操作系统上运行程序,并且遇到了权限问题,你可以尝试更改文件或文件夹的所有者。使用chown命令可以更改文件或文件夹的所有者,例如: ```shell sudo chown your_username filename ``` 将"your_username"替换为你的用户名,"filename"替换为你要更改所有者的文件或文件夹的路径。 4. 使用sudo命令:如果你是在Linux或Mac操作系统上运行程序,并且遇到了权限问题,你可以尝试使用sudo命令以超级用户身份运行程序。使用sudo命令可以暂时提升你的权限,例如: ```shell sudo python your_program.py ``` 将"your_program.py"替换为你要运行的程序的路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值