月度归档: 2022年3月

LeetCode刷题【237】删除链表中的节点

请编写一个函数,用于 删除单链表中某个特定节点 。在设计函数时需要注意,你无法访问链表的头节点 head ,只能直接访问 要被删除的节点

题目数据保证需要删除的节点 不是末尾节点

 

示例 1:

输入:head = [4,5,1,9], node = 5
输出:[4,1,9]
解释:指定链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9

示例 2:

输入:head = [4,5,1,9], node = 1
输出:[4,5,9]
解释:指定链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9

示例 3:

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

示例 4:

输入:head = [0,1], node = 0
输出:[1]

示例 5:

输入:head = [-3,5,-99], node = -3
输出:[5,-99]

 

提示:

  • 链表中节点的数目范围是 [2, 1000]
  • -1000 <= Node.val <= 1000
  • 链表中每个节点的值都是唯一的
  • 需要删除的节点 node链表中的一个有效节点 ,且 不是末尾节点
Related Topics
  • 链表

  • 👍 1119
  • 👎 0
  • 简单,1赋值,2修改指针

    1. 当前节点值改为下一个节点的值
    2. 当前节点的next改为下一个节点的next
    class Solution {
        public void deleteNode(ListNode node) {
            ListNode next = node.next;
            node.val = next.val;
            node.next = next.next;
        }
    }

    LeetCode刷题【79】单词搜索

    给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false

    单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

     

    示例 1:

    输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
    输出:true
    

    示例 2:

    输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
    输出:true
    

    示例 3:

    输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
    输出:false
    

     

    提示:

    • m == board.length
    • n = board[i].length
    • 1 <= m, n <= 6
    • 1 <= word.length <= 15
    • boardword 仅由大小写英文字母组成

     

    进阶:你可以使用搜索剪枝的技术来优化解决方案,使其在 board 更大的情况下可以更快解决问题?

    Related Topics
  • 数组
  • 回溯
  • 矩阵

  • 👍 1224
  • 👎 0
  • 标准回溯题

    1. 挨个遍历找首字母匹配
    2. 从匹配的首字母开始往四个方向遍历匹配下一个字母,并记录已访问过的点坐标
    3. 遍历的过程中如果有字母不匹配返回false
    4. 遍历的过程中判断越界情况和已访问过的情况
    5. 直到匹配到最后一个字符完全相同 返回false
    6. 退出递归记得改掉已访问过的坐标为false
    class Solution {
    
        char[][] board;
        int[][] target = {{1,0},{0,1},{-1,0},{0,-1}};
        String word;
    
        public boolean exist(char[][] board, String word) {
            this.board = board;
            this.word = word;
            boolean[][] visited = new boolean[board.length][board[0].length];
            for (int row = 0; row < board.length; row++) {
                for (int col = 0; col < board[0].length; col++) {
                    visited[row][col] = true;
                    if (board[row][col] == word.charAt(0) && dfs(row,col, visited, 0)){
                        return true;
                    }
                    visited[row][col] = false;
                }
            }
            return false;
        }
    
    
    
        private boolean dfs(int row, int col, boolean[][] visited, int idx){
            if (idx== word.length()-1 && word.charAt(idx)==board[row][col]){
                return true;
            }
    
            if (word.charAt(idx) != board[row][col]){
                return false;
            }
            for (int[] ints : target) {
                int nextRow = row+ints[0];
                int nextCol = col+ints[1];
                if (nextRow>= board.length || nextRow < 0 || nextCol >= board[0].length || nextCol < 0 || visited[nextRow][nextCol]){
                    continue;
                }
                visited[nextRow][nextCol] = true;
                if (dfs(nextRow,nextCol, visited,idx+1)){
                    return true;
                }
                visited[nextRow][nextCol] = false;
            }
            return false;
        }
    }

    LeetCode刷题【剑指 Offer 67】把字符串转换成整数

    写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。

     

    首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。

    当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。

    该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。

    注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。

    在任何情况下,若函数不能进行有效的转换时,请返回 0。

    说明:

    假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231,  231 − 1]。如果数值超过这个范围,请返回  INT_MAX (231 − 1) 或 INT_MIN (−231) 。

    示例 1:

    输入: "42"
    输出: 42
    

    示例 2:

    输入: "   -42"
    输出: -42
    解释: 第一个非空白字符为 '-', 它是一个负号。
         我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
    

    示例 3:

    输入: "4193 with words"
    输出: 4193
    解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
    

    示例 4:

    输入: "words and 987"
    输出: 0
    解释: 第一个非空字符是 'w', 但它不是数字或正、负号。
         因此无法执行有效的转换。

    示例 5:

    输入: "-91283472332"
    输出: -2147483648
    解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 
         因此返回 INT_MIN (−231) 。
    

     

    注意:本题与主站 8 题相同:https://leetcode-cn.com/problems/string-to-integer-atoi/

    Related Topics
  • 字符串

  • 👍 148
  • 👎 0
  • java数字模拟,更新

    数字模拟题

    1. 找到第一个非空字符
    2. 如果不是-``+``0123456789的话返回0
    3. 如果是-``+,处理符号位,并下标往后移动一位
    4. 后面一直遍历直到取到的字符不是数字,
    5. 在遍历过程中如果是正数,如果前面大于Integer.MAX_VALUE/10或者前面等于Integer.MAX_VALUE/10且当前数字大于7,会越界,返回Integer.MAX_VALUE
    6. 如果是负数,如果前面大于Integer.MAX_VALUE/10或者前面等于Integer.MAX_VALUE/10且当前数字大于8,会越界,返回Integer.MIN_VALUE
    7. 否则之前值乘以10 加上当前值
    8. 最终返回的时候加上符号位
    class Solution {
        public int strToInt(String str) {
            if (str.length()==0){
                return 0;
            }
            int idx = -1;
            while (++idx<str.length() && str.charAt(idx)==' '){}
            if (idx==str.length()){
                return 0;
            }
            if (str.charAt(idx)!='-' && str.charAt(idx)!='+' && (str.charAt(idx)-'0'<0 || str.charAt(idx)-'0'>9)){
                return 0;
            }
            boolean flag = true;
            if (str.charAt(idx)=='-' || str.charAt(idx)=='+'){
                flag = str.charAt(idx) != '-';
                idx++;
            }
    
            int res = 0;
            idx--;
            while (++idx<str.length() && str.charAt(idx)-'0'>=0 && str.charAt(idx)-'0'<=9){
                if (flag){
                    if (res > Integer.MAX_VALUE/10 || (res == Integer.MAX_VALUE/10 && str.charAt(idx)-'0'> 7)){
                        return Integer.MAX_VALUE;
                    }
                }else{
                    if (res > Integer.MAX_VALUE/10 || (res == Integer.MAX_VALUE/10 && str.charAt(idx)-'0'> 8)){
                        return Integer.MIN_VALUE;
                    }
                }
                res = res * 10 + ( str.charAt(idx)-'0');
            }
    
            return flag?res:-res;
        }
    }

    今天重新做了一次,比之前应该好看点代码

    class Solution {
        public int strToInt(String str) {
            int idx = -1;
            while (++idx < str.length() && str.charAt(idx)==' '){}
            if (idx  == str.length()){
                return 0;
            }
            int flag = 1;
            if (str.charAt(idx) == '-'){
                idx++;
                flag = -1;
            }else if (str.charAt(idx) == '+'){
                idx++;
            }
            int ans = 0;
            int limitL = Integer.MIN_VALUE/10;
            int limitLL = -Integer.MIN_VALUE%10;
            int limitR = Integer.MAX_VALUE/10;
            int limitRR = Integer.MAX_VALUE%10;
            while (idx < str.length() && str.charAt(idx)- '0' >= 0 && str.charAt(idx)-'9' <= 0){
                int num = flag * (str.charAt(idx)- '0');
                if (ans < limitL ||  (ans == limitL && num < limitLL)){
                    return Integer.MIN_VALUE;
                }
                if (ans > limitR ||  (ans == limitR && num > limitRR)){
                    return Integer.MAX_VALUE;
                }
                ans *=10;
                ans += num;
                idx++;
            }
            return ans;
        }
    }

    LeetCode刷题【剑指 Offer 66】构建乘积数组

    给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B[i] 的值是数组 A 中除了下标 i 以外的元素的积, 即 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。

     

    示例:

    输入: [1,2,3,4,5]
    输出: [120,60,40,30,24]

     

    提示:

    • 所有元素乘积之和不会溢出 32 位整数
    • a.length <= 100000
    Related Topics
  • 数组
  • 前缀和

  • 👍 206
  • 👎 0

  • 前年美团面试遇到过,哎,更新下(前缀 和×,积√),同力扣238题

    当时没做出来,只是灵光一闪想到了可以全乘了然后除以各个数字,后来加了不能用除法的条件后,想了下觉得可能分段预先把个部分分段区间的乘积求起来,但是后来就没后来了。

    最终结果可以直接在int[] a数组上修改,省一点空间?或者其实还可以再极限一点把int[] arrint[] arr2声明成一个数组,然后在运算的key上做文章

    class Solution {
        public int[] constructArr(int[] a) {
            int n = a.length;
            if (n==0){
                return a;
            }
            int[] arr = new int[n];
            int[] arr2 = new int[n];
    
            arr[0] = a[0];
            arr2[n-1] = a[n-1];
            for (int idx = 1; idx < n; idx++) {
                arr[idx] = a[idx]* arr[idx-1];
                int backIdx = n-idx-1;
                arr2[backIdx] = a[backIdx] * arr2[backIdx+1];
            }
            a[0] = arr2[1];
            a[n-1] = arr[n-2];
            for (int i = 1; i < a.length-1; i++) {
                a[i] = arr[i-1] * arr2[i+1];
            }
            return a;
        }
    }

    重新做这题,更新下单数组解法, 同力扣238题,不过238题的测试用例没有空数组的情况
    思路还是一样的,就是先后更新的时候算的问题

    class Solution {
        public int[] constructArr(int[] nums) {
            if (nums.length < 2){
                return nums;
            }
            int[] res = new int[nums.length];
            res[0] = 1;
            for (int i = 1; i < nums.length; i++) {
                res[i] = res[i-1] * nums[i-1];
            }
            int preR =  nums[nums.length-1];
            for (int r = nums.length-2; r >= 0; r--) {
                res[r] *= preR;
                preR *= nums[r];
            }
            return res;
        }
    }

    LeetCode刷题【575】分糖果

    Alice 有 n 枚糖,其中第 i 枚糖的类型为 candyType[i] 。Alice 注意到她的体重正在增长,所以前去拜访了一位医生。

    医生建议 Alice 要少摄入糖分,只吃掉她所有糖的 n / 2 即可(n 是一个偶数)。Alice 非常喜欢这些糖,她想要在遵循医生建议的情况下,尽可能吃到最多不同种类的糖。

    给你一个长度为 n 的整数数组 candyType ,返回: Alice 在仅吃掉 n / 2 枚糖的情况下,可以吃到糖的 最多 种类数

     

    示例 1:

    输入:candyType = [1,1,2,2,3,3]
    输出:3
    解释:Alice 只能吃 6 / 2 = 3 枚糖,由于只有 3 种糖,她可以每种吃一枚。
    

    示例 2:

    输入:candyType = [1,1,2,3]
    输出:2
    解释:Alice 只能吃 4 / 2 = 2 枚糖,不管她选择吃的种类是 [1,2]、[1,3] 还是 [2,3],她只能吃到两种不同类的糖。
    

    示例 3:

    输入:candyType = [6,6,6,6]
    输出:1
    解释:Alice 只能吃 4 / 2 = 2 枚糖,尽管她能吃 2 枚,但只能吃到 1 种糖。
    

     

    提示:

    • n == candyType.length
    • 2 <= n <= 104
    • n 是一个偶数
    • -105 <= candyType[i] <= 105
    Related Topics
  • 数组
  • 哈希表

  • 👍 200
  • 👎 0
  • 哈希表简单处理

    没啥太复杂的,直接看代码

    class Solution {
        public int distributeCandies(int[] candyType) {
            HashSet<Integer> hashSet = new HashSet<>();
            for (int i : candyType) {
                hashSet.add(i);
                if (hashSet.size()>=candyType.length/2){
                    return hashSet.size();
                }
            }
            return hashSet.size();
        }
    }
    1. candyType长度为偶数,所以直接声明一个哈希表hashSet,往这个表里尽量放入不同的糖果,如果种数类型已经满足了candyType的一半,就可以直接返回了
    2. 如果到了最终仍然没有满足candyType的长度的一半,则最终反返回hashSet的长度

    LeetCode刷题【500】键盘行

    给你一个字符串数组 words ,只返回可以使用在 美式键盘 同一行的字母打印出来的单词。键盘如下图所示。

    美式键盘 中:

    • 第一行由字符 "qwertyuiop" 组成。
    • 第二行由字符 "asdfghjkl" 组成。
    • 第三行由字符 "zxcvbnm" 组成。

     

    示例 1:

    输入:words = ["Hello","Alaska","Dad","Peace"]
    输出:["Alaska","Dad"]
    

    示例 2:

    输入:words = ["omk"]
    输出:[]
    

    示例 3:

    输入:words = ["adsdf","sfd"]
    输出:["adsdf","sfd"]
    

     

    提示:

    • 1 <= words.length <= 20
    • 1 <= words[i].length <= 100
    • words[i] 由英文字母(小写和大写字母)组成
    Related Topics
  • 数组
  • 哈希表
  • 字符串

  • 👍 202
  • 👎 0
  • 凑合一个哈希表

    class Solution {
        public String[] findWords(String[] words) {
            String s1 = "qwertyuiopQWERTYUIOP";
            String s2 = "asdfghjklASDFGHJKL";
            String s3 = "zxcvbnmZXCVBNM";
            HashMap<Character,Integer> hashMap = new HashMap<>();
            for (int i = 0; i < s1.length(); i++) {
                hashMap.put(s1.charAt(i),1);
            }
            for (int i = 0; i < s2.length(); i++) {
                hashMap.put(s2.charAt(i),2);
            }
            for (int i = 0; i < s3.length(); i++) {
                hashMap.put(s3.charAt(i),3);
            }
            List<String> res = new ArrayList<>();
            for (String word : words) { ;
                if (word.length()==1){
                    res.add(word);
                    continue;
                }
                int i = 1;
                for (; i < word.length(); i++) {
                    if (!hashMap.get(word.charAt(i)).equals(hashMap.get(word.charAt(i - 1)))){
                        break;
                    }
                    if (i==word.length()-1){
                        res.add(word);
                    }
                }
    
            }
            return res.toArray(new String[0]);
        }
    }

    LeetCode刷题【128】最长连续序列

    给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

    请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

     

    示例 1:

    输入:nums = [100,4,200,1,3,2]
    输出:4
    解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。

    示例 2:

    输入:nums = [0,3,7,2,5,8,4,6,0,1]
    输出:9
    

     

    提示:

    • 0 <= nums.length <= 105
    • -109 <= nums[i] <= 109
    Related Topics
  • 并查集
  • 数组
  • 哈希表

  • 👍 1154
  • 👎 0
  • 哈希表,一次遍历,时间复杂度为 O(n) ,并不需要再往当前值两边遍历查询【更新图解】的解法

    以题面中的例子为例分析

    nums = [0,3,7,2,5,8,4,6,0,1]

    我们建立一个HashMap,key存储的是某个数字,value存储的是这个数字对应的连续区间的长度

    但是我们真的需要在每插入一个数字的时候,更新整个对应的连续区间里的所有数字的对应连续区间的长度么?

    答案是肯定的 “不”

    如上面的举例数组,我们来尝试分析下

    1. 当第一个数字0的时候,我们在哈希表中插入一个记录key=0,value=1
    2. 当面有第二个数字3的时候,继续在哈希表中插入一个记录,key=3,value=1
    3. 下一个7,相同key=7,value=1
    4. 这时候我们遇到了数字2,在插入哈希表之后,判断下,此时哈希表中有1么?没有,那么跳过。但是又有没有3呢?有的,3对应的长度为1,所以我们知道了哈希表中此时应当更新这些信息:key=2,value=2;key=3,value=2
    5. 后面太多距离太远的,为了减少分析中的情况讨论暂时忽略。
    6. 然后我们来到了数字4,此时我们发现前面有个3,他对应的长度是2,那么我们应该把4对应的长度更新为3,而3前面对应的长度2的开头key=2的位置也应当更新为长度3,就有了key=4,value=3;key=2,value=3
    7. 直接到结尾数字0 的时候,此时哈希表中已经有了0了,可以直接跳过
    8. 最后遇到了数字1,在这里我们先确认下此时哈希表中的值,这里将是最关键的一步
    key=0, value = 1
    key=2, value = 3
    key=3, value = 2
    key=4, value = 3

    1的左边有0,长度为1,同时右边有2,长度为3,所以能够组合得到的长度是

    左边的长度1 + 右边的长度3 + 1数字本身的长度1 = 长度5

    最终这里的哈希表中的值的情况如下

    key=0, value = 5
    key=1, value = 1
    key=2, value = 3
    key=3, value = 2
    key=4, value = 5

    在这个结果中,如果又多了一个数字5,需要修改的应该是key=0, value = 6; key=5, value = 6

    到这里其实应当已经非常明了了,下面直接看代码吧

    代码
    class Solution {
        public int longestConsecutive(int[] nums) {
            if (nums.length==0)return 0;
            HashMap<Integer,Integer> map = new HashMap<>();
            int max = 1;
            for (int num : nums) {
                if (map.containsKey(num)){
                    continue;
                }
                map.put(num,1);
                int l = num;
                int r = num;
                int length = 1;
    
                if (map.containsKey(num-1)){
                    l = num - map.get(num-1);
                    length += map.get(l);
                }
                if (map.containsKey(num+1)){
                    r = num + map.get(num+1);
                    length += map.get(num+1);
                }
                map.put(l,length);
                map.put(r,length);
                max = Math.max(max,length);
            }
    
            return max;
        }
    }

    补个画图说明,可能关文字不太好理解?

    横向蓝色的是哈希表的key,竖直方向的橙色为当前遍历到的数字,红色部分为当前遍历的时候插入的值,黄色部分表示当前遍历的时候更新的值

    前面几步太简单,省略了

    直接快进到图上插入数字6的时候讲解,覆盖了完整的判断处理逻辑

    1. 插入数字6,暂时记录哈希表上6对应的值为1
    2. 判断左边一个key 也就是 6-1的情况,读取哈希表key=5的值,知道5对应的最长连续长度为4,那么也就可以知道应该是从数字2到5都有,这样才能得到一个以5结尾的长度4的序列,暂时记下来,我们知道了左边界为2,左边长度为4
    3. 再判断右边,也就是key为7的值,读取哈希表知道了7对应的长度为2,那么也就知道了右边界为8,右边的长度为2
    4. 这样就知道了左边长度是4、右边长度是2,当前数字6还占一个长度1,那么总连续长度为 4 + 2 + 1 = 7
    5. 更新左右两个边界的key对应的长度、把key=2的左边界value更新为7,把key=8右边界的value更新为7