Page 23 of 61

LeetCode刷题【剑指 Offer II 014】字符串中的变位词

给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的某个变位词。

换句话说,第一个字符串的排列之一是第二个字符串的 子串

 

示例 1:

输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").

示例 2:

输入: s1= "ab" s2 = "eidboaoo"
输出: False

 

提示:

  • 1 <= s1.length, s2.length <= 104
  • s1s2 仅包含小写字母

 

注意:本题与主站 567 题相同: https://leetcode-cn.com/problems/permutation-in-string/

Related Topics
  • 哈希表
  • 双指针
  • 字符串
  • 滑动窗口

  • 👍 29
  • 👎 0

  • 滑动窗口基本思路

    基本滑动窗口算法
    挪一格,修改一下统计数量,然后对比两个数组内是否相同

    class Solution {
        public boolean checkInclusion(String s1, String s2) {
            if (s1.length()>s2.length()){
                return false;
            }
            
            int[] count = new int[26];
            int[] window = new int[26];
            int idx = -1;
            while (++idx < s1.length()){
                count[s1.charAt(idx)-'a']++;
                window[s2.charAt(idx)-'a']++;
            }
            if (Arrays.equals(count,window)){
                return true;
            }
            idx--;
            while (++idx < s2.length()){
                System.out.println( idx );
                window[s2.charAt( idx - s1.length() ) - 'a']--;
                window[s2.charAt( idx ) - 'a']++;
                if (Arrays.equals(count,window)){
                    return true;
                }
            }
            return false;
        }
    
    }

    滑动窗口diffArr判断算法,判断26个字母数量是否为0,如果是都是0则代表能匹配

    class Solution {
        public boolean checkInclusion(String s1, String s2) {
            if (s1.length()>s2.length()){
                return false;
            }
    
            int[] diffArr = new int[26];
            int idx = -1;
            int diffCount = 0;
            while (++idx < s1.length()){
                diffArr[s1.charAt(idx)-'a']++;
                diffArr[s2.charAt(idx)-'a']--;
            }
            boolean flag = true;
            for (int i = 0; i < 26; i++) {
                if (diffArr[i]!=0){
                    flag =false;
                    break;
                }
            }
            if (flag){
                return true;
            }
            --idx;
            while (++idx < s2.length()){
                diffArr[s2.charAt(idx-s1.length())-'a']++;
                diffArr[s2.charAt(idx)-'a']--;
                flag = true;
                for (int i = 0; i < 26; i++) {
                    if (diffArr[i]!=0){
                        flag =false;
                        break;
                    }
                }
                if (flag){
                    return true;
                }
            }
            return false;
        }
    
    }

    第二种滑动窗口的理解稍微绕个弯,每当diffArr中有一个不是0的,说明有一个差异点,
    然后接下来窗口滑动过程中 需要在修改前判断

    1. 这个值是不是0,如果是0,修改了之后diffCount需要加1,
    2. 如果不是0.修改之后会不会变0.如果会变0,diffCount减1
    3. 如果修改后不会变0,则diffCount不需要变更

    if判断太多,效率甚至不如上一个遍历一下长度只有26的diffArr数组

    class Solution {
        public boolean checkInclusion(String s1, String s2) {
            if (s1.length()>s2.length()){
                return false;
            }
    
            int[] diffArr = new int[26];
            int idx = -1;
            int diffCount = 0;
            while (++idx < s1.length()){
                diffArr[s1.charAt(idx)-'a']++;
                diffArr[s2.charAt(idx)-'a']--;
            }
            int i = -1;
            while (++i<26){
                diffCount += diffArr[i]==0?0:1;
            }
            if (diffCount==0){
                return true;
            }
    
            --idx;
            while (++idx < s2.length()){
                int before = s2.charAt(idx-s1.length())-'a';
                int current = s2.charAt(idx)-'a';
                if (before == current){
                    continue;
                }
                if (diffArr[before]==-1){
                    diffCount--;
                }
                if (diffArr[before] == 0){
                    diffCount++;
                }
                diffArr[before]++;
    
                if (diffArr[current]==1){
                    diffCount--;
                }
                if (diffArr[current]==0){
                    diffCount++;
                }
                diffArr[current]--;
                if (diffCount == 0){
                    return true;
                }
            }
            return false;
        }
    
    }

    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]);
        }
    }