作者: CheungQ

LeetCode刷题【7】整数反转

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231,  231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

 

示例 1:

输入:x = 123
输出:321

示例 2:

输入:x = -123
输出:-321

示例 3:

输入:x = 120
输出:21

示例 4:

输入:x = 0
输出:0

 

提示:

  • -231 <= x <= 231 - 1
Related Topics
  • 数学

  • 👍 3012
  • 👎 0
  • 题解

    简单题,最直接的思路就是翻转了,但是还有个符号位,所以符号位的逻辑要额外处理下。刷题刷得可嗨了……被同事看到了,然后他也想试试,emm过了半天跑来问我这题。顺手写下再给他讲下。

    /**
     * 字符串拼接转换,性能较低
     * 解答成功:
     * 执行耗时:3 ms,击败了16.46% 的Java用户
     * 内存消耗:35.7 MB,击败了19.93% 的Java用户
     * @param x
     * @return
     */
    public int reverse(int x) {
        String str = Integer.toString(x);
        char[] arr = str.toCharArray();
        int left = 0;
        int right = arr.length-1;
        if (arr[0]=='-'){
            left=1;
        }
        char tmp;
        while (left<right){
            tmp = arr[left];
            arr[left]=arr[right];
            arr[right]=tmp;
            left++;
            right--;
        }
        String newStr = new String(arr);
        int newInt;
        try {
            newInt = Integer.parseInt(newStr);
        }catch (NumberFormatException e){
            //用了异常来实现逻辑、这种方法在实际编码中绝对绝对不可取
            return 0;
        }
        return newInt;
    }

    但是这边用了个try/catch来处理异常来实现逻辑上的处理,这种处理办法应该是绝对禁止的,非常不符合代码规范。而且try/catch带来的性能损失应该也是不小的。

    所以,更好的办法如下:

    /**
     * 数学计算绝对不溢出方法
     * 解答成功:
     * 执行耗时:1 ms,击败了100.00% 的Java用户
     * 内存消耗:35.6 MB,击败了39.89% 的Java用户
     *
     * @param x
     * @return
     */
    public int reverse2(int x) {
        String str = Integer.toString(x);
        char[] arr = str.toCharArray();
        x = 1;
        int limit = 0;
        if (arr[0]=='-'){
            x = -1;
            limit = 1;
            arr[0] = '0';
        }
        int num = 0;
        for (int i = str.length()-1; i >= limit; i--) {
            num = num*10 + (arr[i]-'0');
            if (i==limit+1){
                if (Integer.MAX_VALUE/10 <num || (Integer.MAX_VALUE/10 == num*10 && Integer.MAX_VALUE%10 < (arr[limit]-'0'))){
                    return 0;
                }
            }
        }
        return x*num;
    }

    这边溢出判断用了Integer.MAX_VALUE/10来处理,这样能有效避免溢出的问题。另外也有想过溢出后正负数相乘应该为负数这种方法来判断,但是实际数据表明……..乘以10之后溢出的话,仍然可能还为正数,指多绕了几圈又绕回正数区间了,然后再相乘的话是一个更加更加大的数值,依然可能为正数,所以这种判断方式不可取。必须老老实实用Integer.MAX_VALUE/10和还没乘以10进位的数字大小做比较。

    顺便,评论区有个这么一个答题内容

        public int reverse(int x) {
            long n = 0;
            while(x != 0) {
                n = n*10 + x%10;
                x = x/10;
            }
            return (int)n==n? (int)n:0;
        }

    一眼看到好惊艳,但是再看下其实不对劲。关键在这里

    long n = 0;

    long类型变量的存在就忽略了题中要求的“假设环境不允许存储 64 位整数(有符号或无符号)。”

    LeetCode刷题【1487】保证文件名唯一

    给你一个长度为 n 的字符串数组 names 。你将会在文件系统中创建 n 个文件夹:在第 i 分钟,新建名为 names[i] 的文件夹。

    由于两个文件 不能 共享相同的文件名,因此如果新建文件夹使用的文件名已经被占用,系统会以 (k) 的形式为新文件夹的文件名添加后缀,其中 k 是能保证文件名唯一的 最小正整数

    返回长度为 n 的字符串数组,其中 ans[i] 是创建第 i 个文件夹时系统分配给该文件夹的实际名称。

     

    示例 1:

    输入:names = ["pes","fifa","gta","pes(2019)"]
    输出:["pes","fifa","gta","pes(2019)"]
    解释:文件系统将会这样创建文件名:
    "pes" --> 之前未分配,仍为 "pes"
    "fifa" --> 之前未分配,仍为 "fifa"
    "gta" --> 之前未分配,仍为 "gta"
    "pes(2019)" --> 之前未分配,仍为 "pes(2019)"
    

    示例 2:

    输入:names = ["gta","gta(1)","gta","avalon"]
    输出:["gta","gta(1)","gta(2)","avalon"]
    解释:文件系统将会这样创建文件名:
    "gta" --> 之前未分配,仍为 "gta"
    "gta(1)" --> 之前未分配,仍为 "gta(1)"
    "gta" --> 文件名被占用,系统为该名称添加后缀 (k),由于 "gta(1)" 也被占用,所以 k = 2 。实际创建的文件名为 "gta(2)" 。
    "avalon" --> 之前未分配,仍为 "avalon"
    

    示例 3:

    输入:names = ["onepiece","onepiece(1)","onepiece(2)","onepiece(3)","onepiece"]
    输出:["onepiece","onepiece(1)","onepiece(2)","onepiece(3)","onepiece(4)"]
    解释:当创建最后一个文件夹时,最小的正有效 k 为 4 ,文件名变为 "onepiece(4)"。
    

    示例 4:

    输入:names = ["wano","wano","wano","wano"]
    输出:["wano","wano(1)","wano(2)","wano(3)"]
    解释:每次创建文件夹 "wano" 时,只需增加后缀中 k 的值即可。

    示例 5:

    输入:names = ["kaido","kaido(1)","kaido","kaido(1)"]
    输出:["kaido","kaido(1)","kaido(2)","kaido(1)(1)"]
    解释:注意,如果含后缀文件名被占用,那么系统也会按规则在名称后添加新的后缀 (k) 。
    

     

    提示:

    • 1 <= names.length <= 5 * 10^4
    • 1 <= names[i].length <= 20
    • names[i] 由小写英文字母、数字和/或圆括号组成。
    Related Topics
  • 数组
  • 哈希表
  • 字符串

  • 👍 31
  • 👎 0
  • 题解

    class Solution {
        HashMap<String,Integer> hashMap = new HashMap<>();
        public String[] getFolderNames(String[] names) {
            for (int i = 0; i < names.length; i++) {
                names[i] = putName(names[i], 0);
            }
            return names;
        }
    
        public String putName(String name, int num){
            String newName;
            while (true){
                newName= num==0?name:name+"("+num+")";
                if (!hashMap.containsKey(newName)){
                    hashMap.put(newName,0);
                    if (num>0){
                        hashMap.put(name,num);
                    }
                    break;
                }
                hashMap.put(name,hashMap.get(name)+1);
                num = hashMap.get(name);
            }
            return newName;
        }
    }

    原本在这个之前写过一版,超时,32 / 33 个通过测试用例,在最后一个超长的测试用力的时候超时了,所以再这个基础上再加改进,改原来的hashset为map,额外统计对应字符已经用过的次数,下次遇到冲突的时候根据之前的记忆来获取新的key。

    class Solution {
        HashSet<String> hashSet = new HashSet<>();
        public String[] getFolderNames(String[] names) {
            for (int i = 0; i < names.length; i++) {
                names[i] = putName(names[i], 0);
            }
            return names;
        }
    
        public String putName(String name, int num){
            String newName = num==0?name:name+"("+num+")";
            if (!hashSet.contains(newName)){
                hashSet.add(newName);
                return newName;
            }
            return putName(name,num+1);
        }
    }

    有一点就是 如果在已经输入了“abc”,“abc(1)”的情况下,再次输入“abc”,
    此时记录的数量应该为:
    “abc”1次
    “abc(1)”1次

    需要新增一个key=“abc”的记录,发现已有再次尝试“abc(1)”还是已有的情况下,需要对“abc”的数量修正加1
    此时变成:
    “abc”2次
    “abc(1)”1次

    这样能把之前的输入“abc(1)”的时候没有去给“abc”加1的误差修正回来,便于本次插入的统计,而最终结果只要是能插入就行,后续还有其他的中间状态的统计不正确并不需要去修正处理。

    当然这边你也可以选择对插入的文件名进行判断括号字符串,找到除去括号外的真实文件名,但是我觉得这种做法有点点点…..不大优雅….吧,或者说有点点傻….

    还有一点就是在getFolderNames中的for循环遍历中,直接修改当前插入的字符串的存到对应位置,最终仍旧是返回String[] names数组,无需额外声明数组开辟新的内存空间。

    LeetCode刷题 【1539】第k个缺失的正整数

    给你一个 严格升序排列 的正整数数组 arr 和一个整数 k 。

    请你找到这个数组里第 k 个缺失的正整数。

     

    示例 1:

    输入:arr = [2,3,4,7,11], k = 5
    输出:9
    解释:缺失的正整数包括 [1,5,6,8,9,10,12,13,...] 。第 5 个缺失的正整数为 9 。
    

    示例 2:

    输入:arr = [1,2,3,4], k = 2
    输出:6
    解释:缺失的正整数包括 [5,6,7,...] 。第 2 个缺失的正整数为 6 。
    

     

    提示:

    • 1 <= arr.length <= 1000
    • 1 <= arr[i] <= 1000
    • 1 <= k <= 1000
    • 对于所有 1 <= i < j <= arr.length 的 i 和 j 满足 arr[i] < arr[j] 
    Related Topics
  • 数组
  • 二分查找

  • 👍 52
  • 👎 0
  • 题解

    一次遍历记录丢失差值数量,如果有返回对应的位置的数字。如果遍历内没能找到,则表述数组是连续完整递增的,则返回数组长度加k位的

    class Solution {
        public int findKthPositive(int[] arr, int k) {
    
            int cur = 0;
            int missingCount = 0;
            while (cur < arr.length){
                while (cur+missingCount+1 < arr[cur]){
                    missingCount++;
                    if (missingCount==k){
                        return cur+missingCount;
                    }
                }
                cur++;
            }
            return arr.length+k;
        }
    }

    LeetCode刷题 【1】两数之和

    给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

    你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

    你可以按任意顺序返回答案。

     

    示例 1:

    输入:nums = [2,7,11,15], target = 9
    输出:[0,1]
    解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
    

    示例 2:

    输入:nums = [3,2,4], target = 6
    输出:[1,2]
    

    示例 3:

    输入:nums = [3,3], target = 6
    输出:[0,1]
    

     

    提示:

    • 2 <= nums.length <= 104
    • -109 <= nums[i] <= 109
    • -109 <= target <= 109
    • 只会存在一个有效答案

    进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?

    Related Topics
  • 数组
  • 哈希表

  • 👍 11883
  • 👎 0
  • 题解


    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
    public int[] twoSum(int[] nums, int target) {
    HashMap<Integer,Integer> map = new HashMap<>();
    int[] res = new int[2];
    for (int i = 0; i < nums.length; i++) {
    int otherNum = target-nums[i];
    if (map.containsKey(otherNum) && map.get(otherNum)!=i){
    res[0] = map.get(otherNum);
    res[1] = i;
    }
    map.put(nums[i], i);
    }
    return res;
    }
    }
    //leetcode submit region end(Prohibit modification and deletion)

    LeetCode刷题 【1646】获取生成数组中的最大值

    8月23每日一题

    力扣插件挂了,获取不到题面列表,我也拿不到题面的html代码了。。

    给你一个整数 n 。按下述规则生成一个长度为 n + 1 的数组 nums :

    • nums[0] = 0
    • nums[1] = 1
    • 当 2 <= 2 * i <= n 时,nums[2 * i] = nums[i]
    • 当 2 <= 2 * i + 1 <= n 时,nums[2 * i + 1] = nums[i] + nums[i + 1]

    返回生成数组 nums 中的 最大 值。

    示例 1:

    输入:n = 7
    输出:3
    解释:根据规则:
      nums[0] = 0
      nums[1] = 1
      nums[(1 * 2) = 2] = nums[1] = 1
      nums[(1 * 2) + 1 = 3] = nums[1] + nums[2] = 1 + 1 = 2
      nums[(2 * 2) = 4] = nums[2] = 1
      nums[(2 * 2) + 1 = 5] = nums[2] + nums[3] = 1 + 2 = 3
      nums[(3 * 2) = 6] = nums[3] = 2
      nums[(3 * 2) + 1 = 7] = nums[3] + nums[4] = 2 + 1 = 3
    因此,nums = [0,1,1,2,1,3,2,3],最大值 3
    

    示例 2:

    输入:n = 2
    输出:1
    解释:根据规则,nums[0]、nums[1] 和 nums[2] 之中的最大值是 1

    题解

    emmm简单题,直接按照题意把代码撸一下

    public int getMaximumGenerated(int n) {
        int[] nums = new int[n + 1];
        if (n == 0) {
            return nums[0];
        }
        nums[1] = 1;
        int maxNum = 1;
        for (int i = 1; 2 * i <= n || 2 * i + 1 <= n; i++) {
            nums[2 * i] = nums[i];
            maxNum = Math.max(maxNum, nums[2 * i]);
            if (2 * i + 1 <= n) {
                nums[2 * i + 1] = nums[i] + nums[i + 1];
                maxNum = Math.max(maxNum, nums[2 * i + 1]);
            }
        }
        return maxNum;
    }

    简单模拟计算。另外有个规律其实,最大值总是出现在奇数位上的。所以求max的操作只要在奇数位、即if (2 * i + 1 <= n)的判断体内部执行应该就可以了

    LeetCode刷题 【117】填充每个节点的下一个右侧节点指针 II

    给定一个二叉树

    struct Node {
      int val;
      Node *left;
      Node *right;
      Node *next;
    }

    填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL

    初始状态下,所有 next 指针都被设置为 NULL

     

    进阶:

    • 你只能使用常量级额外空间。
    • 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。

     

    示例:

    输入:root = [1,2,3,4,5,null,7]
    输出:[1,#,2,3,#,4,5,7,#]
    解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化输出按层序遍历顺序(由 next 指针连接),'#' 表示每层的末尾。

     

    提示:

    • 树中的节点数小于 6000
    • -100 <= node.val <= 100

     

    Related Topics
  • 深度优先搜索
  • 广度优先搜索
  • 二叉树
  • \n
  • 👍 437
  • 👎 0
  • 题解

    典型BFS遍历

    
    import java.util.LinkedList;
    import java.util.Queue;
    
    class Solution {
        public Node connect(Node root) {
            if (root==null){
                return null;
            }
    
            Queue<Node> queue = new LinkedList<>();
            queue.offer(root);
            while (!queue.isEmpty()){
                Node preNode = null;
                int size = queue.size();
                for (int i = 0; i < size; i++) {
                    Node cur = queue.poll();
                    if (null != preNode){
                        preNode.next = cur;
                    }
                    preNode = cur;
                    if (null!=cur.left){
                        queue.offer(cur.left);
                    }
                    if (null!=cur.right){
                        queue.offer(cur.right);
                    }
                }
            }
    
            return root;
        }
    }

    这边也不一定需要出入队列,直接存链表,依次遍历链接到下一个即可。

    LeetCode刷题 【82】 删除排序链表中的重复元素II

    存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 的数字。

    返回同样按升序排列的结果链表。

     

    示例 1:

    输入:head = [1,2,3,3,4,4,5]
    输出:[1,2,5]
    

    示例 2:

    输入:head = [1,1,1,2,3]
    输出:[2,3]
    

     

    提示:

    • 链表中节点数目在范围 [0, 300]
    • -100 <= Node.val <= 100
    • 题目数据保证链表已经按升序排列
    Related Topics
  • 链表
  • 双指针
  • \n
  • 👍 684
  • 👎 0
  • 题解

    和之前一题LeetCode刷题 【83】 删除排序链表中的重复元素略有不同,这次需要删除的不再是多余的重复元素,而是所有有重复元素的都删除,只留下在原来链表中只出现过一次的节点。

    和官方题解思路有点点点不一样的地方。。

    class Solution {
        public ListNode deleteDuplicates(ListNode head) {
    
            ListNode fakeHead = new ListNode();
            ListNode fakeCurrent = fakeHead;
    
            ListNode current = head;
            int sameVal;
            while (null != current){
                if (current.next!=null && current.val == current.next.val){
                    sameVal = current.val;
                    while (null!=current && current.val == sameVal){
                        current = current.next;
                    }
                }else{
                    fakeCurrent.next = current;
                    current = current.next;
                    fakeCurrent = fakeCurrent.next;
                }
            }
            fakeCurrent.next = null;
            return fakeHead.next;
        }
    }

    新建了一个fakeHead,和对应这个fakeHead往后遍历的fakeCurrent,然后在遍历原链表的时候,用这个fakeCurrent串起来需要的不重复的节点,最终需要把fakeCurrent的next置空。串珠子的意思。。。