• leetcode 困难


    leetcode25

    给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
    k 是一个正整数,它的值小于或等于链表的长度。
    如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

    示例:
    给你这个链表:1->2->3->4->5
    当 k = 2 时,应当返回: 2->1->4->3->5
    当 k = 3 时,应当返回: 3->2->1->4->5

    说明:
    你的算法只能使用常数的额外空间。
    你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    思路一:按部就班,顺序每k个元素进行一次翻转,由此,拆解为 单个长度为k的小链表完全翻转,和将整个列表处理成长度为k的小链(就地翻转)
    1.长度为k的链表翻转部分
    首先要理解链表翻转的本质,即如果t指向当前需要翻转的节点,则需要将t指向t.next的指针指向t的前一个节点(单向链表),为了翻转的连续进行,则需要在翻转前保存pre和next两个指针

    链表翻转前

    链表翻转

    移动pre

    移动t

    移动next,下一次翻转

    翻转

    移动pre2

    移动t

    移动next

    翻转完成

    这就是一个链表翻转的过程,由于end之后不一定为null,所以控制条件需要注意:

    //单个列表反转
        public static ListNode reverseOne(ListNode start,ListNode end){
            if(start==null||end == null)return null;
            ListNode pre=null,t=start,next = t;
            while(t!=null&&pre!=end){
                next = t.next;
                //调整指针
                t.next = pre;
                //更新上面的量
                pre = t;
                t = next;
            }
            return end;
        }
    

    2.整个链表按照长度为k进行翻转
    标记start
    标记end
    翻转链表
    处理指针
    标记start
    标记end
    翻转链表
    处理指针

    //按k个为一组进行反转
        public static ListNode reverseKGroup(ListNode head, int k) {
            ListNode start= head,end=null;
            ListNode v = new ListNode();
            ListNode pre = v,next;
            ListNode h = head;
    
            for(int c=0;h!=null;h=next,c++){
                next = h.next;
                if(c%k==0)start = h;  
                if(c%k==k-1) {
                    //标记end
                    end = h;
                    reverseOne(start,end);
                    //处理指针
                    start.next = next;
                    pre.next = end;
                    pre = start;
                }
            }
            
            return v.next;
        }
    

    题解

    class Solution {
    
        //单个列表反转
        public static ListNode reverseOne(ListNode start,ListNode end){
            if(start==null||end == null)return null;
            ListNode pre=null,t=start,next = t;
            while(t!=null&&pre!=end){
                next = t.next;
                //调整指针
                t.next = pre;
                //更新上面的量
                pre = t;
                t = next;
            }
            return end;
        }
    
        public ListNode reverseKGroup(ListNode head, int k) {
    
            ListNode start= head,end=null;
            ListNode v = new ListNode();
            ListNode pre = v,next;
            ListNode h = head;
    
            for(int c=0;h!=null;h=next,c++){
                next = h.next;
                if(c%k==0)start = h;  
                if(c%k==k-1) {
                    //标记end
                    end = h;
                    reverseOne(start,end);
                    //处理指针
                    start.next = next;
                    pre.next = end;
                    pre = start;
                }
            }
            
            return v.next;
        }
    }
    

    leetcode 30

    给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。

    注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。

    示例 1:

    输入:
    s = "barfoothefoobarman",
    words = ["foo","bar"]
    输出:[0,9]
    解释:
    从索引 0 和 9 开始的子串分别是 "barfoo" 和 "foobar" 。
    输出的顺序不重要, [9,0] 也是有效答案。

    示例 2:

    输入:
    s = "wordgoodgoodgoodbestword",
    words = ["word","good","best","word"]
    输出:[]

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    思路

    单词长度都一样,提示采用滑动窗口

    需要注意:

    1. 滑动外层是按照字符个数
    2. 滑动内层是按照单词
    class Solution {
        public List<Integer> findSubstring(String s, String[] words) {
            List<Integer> res = new ArrayList<>();
            
            if(words.length==0)return res;
            int wl = words[0].length();
            if(s.length()<wl)return res;
            //统计单词表中的个数
            Map<String,Integer> wordSet = new HashMap<>();
            for(String word:words){
                wordSet.put(word,wordSet.getOrDefault(word,0)+1);
            }
            
            //注意滑动不是按单词长度而是按字符
            for(int i=0;i<wl;i++){
                int start=i,end=i,cnt =0;
                //统计字符串中出现的个数
                Map<String,Integer> wordMap = new HashMap<>();
                
                //内层按照单词长度开始滑动
                while(end+wl<=s.length()){
                    String word = s.substring(end, end+wl);
                    end +=wl;
                    //不含有该单词
                    if(!wordSet.keySet().contains(word)){
                        cnt =0;
                        start = end;
                        wordMap.clear();//中间不能有间隔
                    }
                    //含有该单词
                    else{
                        wordMap.put(word, wordMap.getOrDefault(word,0)+1);
                        cnt++;
                        while(wordMap.get(word)>wordSet.get(word)){
                            String popWord = s.substring(start,start+wl);
                            start += wl;
                            cnt--;
                            wordMap.put(popWord, wordMap.get(popWord)-1);
                        }
                        if(cnt==words.length)res.add(start);
                    }
                }
    
            }
            return res;
        }
    }
    

    leetcode 37

    编写一个程序,通过填充空格来解决数独问题。

    一个数独的解法需遵循如下规则:

    数字 1-9 在每一行只能出现一次。
    数字 1-9 在每一列只能出现一次。
    数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
    

    空白格用 '.' 表示。

    一个数独。

    答案被标成红色。

    提示:

    给定的数独序列只包含数字 1-9 和字符 '.' 。
    你可以假设给定的数独只有唯一解。
    给定数独永远是 9x9 形式的。
    

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/sudoku-solver
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    思路一: 回溯法

    lass Solution {
        boolean[][] cols = new boolean[9][9];
        boolean[][] rows = new boolean[9][9];
        boolean[][][] blocks = new boolean[3][3][9];
        List<Integer[]> spaces = new ArrayList<>();
        boolean valid = false;
    
        public void solveSudoku(char[][] board) {
            
            for(int y =0;y<9;y++){
                for(int x=0;x<9;x++){
                    if(board[y][x]=='.'){
                        spaces.add(new Integer[]{y,x});
                    }
                    else{
                        int digit = board[y][x]-'1';
                        rows[y][digit]=true;
                        cols[x][digit]=true;
                        blocks[y/3][x/3][digit]=true;
                    }
                }
            }
            dfs(board,0);
        }
    
        public void dfs(char[][] board,int step){
            if(step==spaces.size()){
                valid = true;
                return;
            }   
            Integer[] space = spaces.get(step);
            Integer i = space[0],j = space[1];
            for(int digit = 0;digit<9&&!valid;digit++){
                if(!cols[j][digit]&&!rows[i][digit]&&!blocks[i/3][j/3][digit]){
                    cols[j][digit]=rows[i][digit]=blocks[i/3][j/3][digit]=true;
                    board[i][j]= (char)(digit+'1');
                    dfs(board, step+1);
                    cols[j][digit]=rows[i][digit]=blocks[i/3][j/3][digit]=false;
                }
            }
        }
    }
    

    leetcode41

    1. 缺失的第一个正数
      给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

    进阶:你可以实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案吗?

    示例 1:

    输入:nums = [1,2,0]
    输出:3
    示例 2:

    输入:nums = [3,4,-1,1]
    输出:2
    示例 3:

    输入:nums = [7,8,9,11,12]
    输出:1

    提示:

    0 <= nums.length <= 300
    -231 <= nums[i] <= 231 - 1

    package leetcode;
    
    import utils.ArrayUtils;
    
    public class l41 {
        public static int firstMissingPositive(int[] nums) {
            int N = nums.length + 1;
            for (int i = 1; i <= nums.length; i++) {
                if (nums[i - 1] <= 0) nums[i - 1] = N;
            }
            ArrayUtils.printArray(nums);
            for (int i = 1; i <= nums.length; i++) {
                int idx = Math.abs(nums[i - 1]);
                if (idx > 0 && idx < N) {
                    nums[idx - 1] = -Math.abs(nums[idx - 1]);
                }
            }
            ArrayUtils.printArray(nums);
            for (int i = 1; i <= nums.length; i++) {
                if (nums[i - 1] > 0) return i;
            }
            return nums.length + 1;
        }
    
        public static void main(String[] args) {
            int[] nums = {3, 4, -1, 1};
    //        int[] nums = {1, 2, 0};
            ArrayUtils.printArray(nums);
            int res = firstMissingPositive(nums);
            System.out.println(res);
        }
    }
    
    

    leetcode42 接雨水

    给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

    示例 1:

    输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
    输出:6
    解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
    示例 2:

    输入:height = [4,2,0,3,2,5]
    输出:9

    提示:

    n == height.length
    0 <= n <= 3 * 104
    0 <= height[i] <= 105

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/trapping-rain-water
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    
    

    leetcode44

    给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配。

    '?' 可以匹配任何单个字符。
    '*' 可以匹配任意字符串(包括空字符串)。
    两个字符串完全匹配才算匹配成功。

    说明:

    s 可能为空,且只包含从 a-z 的小写字母。
    p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/wildcard-matching
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    package leetcode;
    
    import javafx.scene.effect.DisplacementMap;
    
    public class l44 {
        public static boolean isMatch(String s, String p) {
            //s = "adceb"
            //p = "*a*b"
            char[] sChars = s.toCharArray();
            char[] pChars = p.toCharArray();
            boolean[][] m = new boolean[sChars.length + 1][pChars.length + 1];
            m[0][0] = true;
            for (int i = 1; i <= p.length() && pChars[i - 1] == '*'; i++) {
                m[0][i] = true;
            }
            for (int i = 1; i <= sChars.length; i++) {
                for (int j = 1; j <= pChars.length; j++) {
                    if (pChars[j - 1] == '*') {
                        m[i][j] |= m[i][j - 1];
                        m[i][j] |= m[i - 1][j];
                    } else if (pChars[j - 1] == '?' || sChars[i - 1] == pChars[j - 1]) {
                        m[i][j] |= m[i - 1][j - 1];
                    }
                }
            }
            return m[sChars.length][pChars.length];
        }
    
    
        public static void main(String[] args) {
            String s = "adceb";
    //        String p = "*a*b";
            String p = "a*c?b";
            System.out.println(isMatch(s, p));
        }
    }
    
    
  • 相关阅读:
    JavaScript中出现这个statement expected
    java: 非法字符: 'ufeff' 需要class, interface或enum
    码云如何配置公钥
    Git命令
    配置git签名
    Scanner练习总结
    怎么将项目在Eclipse中生成doc文档
    java文件使用命令生成doc文档
    包机制总结
    变量和运算符总结
  • 原文地址:https://www.cnblogs.com/zhouyu0-0/p/14478479.html
Copyright © 2020-2023  润新知