月度归档: 2022年6月

LeetCode刷题【剑指 Offer 57 – II】和为s的连续正数序列

输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。

序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

 

示例 1:

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

示例 2:

输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]

 

限制:

  • 1 <= target <= 10^5

 

Related Topics
  • 数学
  • 双指针
  • 枚举

  • 👍 449
  • 👎 0
  • 双指针

    class Solution {
        public int[][] findContinuousSequence(int target) {
            int l = 1;
            int r = 2;
            List<int[]> res = new ArrayList<>();
            while (l<r){
                int sum = (l + r) * (r - l + 1) / 2;
                if (sum == target){
                    int[] arr = new int[r - l + 1];
                    int tmp = l-1;
                    while (++tmp <=r){
                        arr[tmp - l] = tmp;
                    }
                    res.add(arr);
                    l++;
                    continue;
                }
                if (sum < target){
                    r++;
                }else{
                    l++;
                }
            }
    
            return res.toArray(new int[res.size()][]);
        }
    }

    LeetCode刷题【剑指 Offer 57】和为s的两个数字

    输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。

     

    示例 1:

    输入:nums = [2,7,11,15], target = 9
    输出:[2,7] 或者 [7,2]
    

    示例 2:

    输入:nums = [10,26,30,31,47,60], target = 40
    输出:[10,30] 或者 [30,10]
    

     

    限制:

    • 1 <= nums.length <= 10^5
    • 1 <= nums[i] <= 10^6
    Related Topics
    • 数组
    • 双指针
    • 二分查找

  • 👍 192
  • 👎 0
  • 哈希表,双指针,二分查找

    1. 哈希表
      这个哈希表有点大
      或者直接用HashSet也可以,性能甚至不如这个boolen[],我试过
    class Solution {
        public int[] twoSum(int[] nums, int target) {
            boolean[] hashSet = new boolean[2000000];
            for (int num : nums) {
                if (hashSet[target-num]){
                    return new int[]{num,target-num};
                }
                hashSet[num] = true;
            }
            return new int[2];
        }
    }
    1. 双指针
      从两边开始往中间找
    class Solution {
        public int[] twoSum(int[] nums, int target) {
            int l = 0;
            int r = nums.length-1;
            while ( l < r){
                int sum = nums[l] + nums[r];
                if(sum == target){
                    return new int[]{nums[l],nums[r]};
                }
                if( sum < target){
                    l++;
                }else{
                    r--;
                }
            }
            return new int[]{nums[l],nums[r]};
        }
    }
    1. 二分
    class Solution {
        public int[] twoSum(int[] nums, int target) {
            int i = -1;
            while (++i < nums.length){
                int s = binarySearch(nums,target- nums[i]);
                if (s >= 0 && i != s){
                    return new int[]{nums[i],nums[s]};
                }
            }
            return new int[2];
        }
    
        int binarySearch(int[] nums, int t ){
            int l = 0;
            int r = nums.length;
            while (l < r){
                int mid = l + ((r-l) >> 1);
                if (nums[mid] == t){
                    return mid;
                }
                if (nums[mid] > t){
                    r = mid;
                }else{
                    l = mid+1;
                }
            }
            return -1;
        }
    }

    LeetCode刷题【1005】K 次取反后最大化的数组和

    给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:

    • 选择某个下标 i 并将 nums[i] 替换为 -nums[i]

    重复这个过程恰好 k 次。可以多次选择同一个下标 i

    以这种方式修改数组后,返回数组 可能的最大和

     

    示例 1:

    输入:nums = [4,2,3], k = 1
    输出:5
    解释:选择下标 1 ,nums 变为 [4,-2,3] 。
    

    示例 2:

    输入:nums = [3,-1,0,2], k = 3
    输出:6
    解释:选择下标 (1, 2, 2) ,nums 变为 [3,1,0,2] 。
    

    示例 3:

    输入:nums = [2,-3,-1,5,-4], k = 2
    输出:13
    解释:选择下标 (1, 4) ,nums 变为 [2,3,-1,5,4] 。
    

     

    提示:

    • 1 <= nums.length <= 104
    • -100 <= nums[i] <= 100
    • 1 <= k <= 104
    Related Topics
    • 贪心
    • 数组
    • 排序

  • 👍 258
  • 👎 0
  • 马马虎虎优先队列

    class Solution {
        public int largestSumAfterKNegations(int[] nums, int k) {
            int sum = 0;
            PriorityQueue<Integer> queue = new PriorityQueue<>();
    
            int absMin = 101;
            for (int num : nums) {
                absMin = Math.min(absMin,Math.abs(num));
                if (num >= 0){
                    sum += num;
                }else{
                    queue.offer(num);
                }
            }
            if (queue.size()>0){
                //把绝对值较大的负数尽量翻转
                while (!queue.isEmpty() && k > 0){
                    sum -= queue.poll();
                    k--;
                }
                if (k==0){
                    //翻转次数用完了,还有数字没翻转
                    while (!queue.isEmpty()){
                        sum += queue.poll();
                    }
                    return sum;
                }
            }
            if (k%2 == 0){
                return sum;
            }else{
                return sum - 2*absMin;
            }
        }
    }

    LeetCode刷题【506】相对名次

    给你一个长度为 n 的整数数组 score ,其中 score[i] 是第 i 位运动员在比赛中的得分。所有得分都 互不相同

    运动员将根据得分 决定名次 ,其中名次第 1 的运动员得分最高,名次第 2 的运动员得分第 2 高,依此类推。运动员的名次决定了他们的获奖情况:

    • 名次第 1 的运动员获金牌 "Gold Medal"
    • 名次第 2 的运动员获银牌 "Silver Medal"
    • 名次第 3 的运动员获铜牌 "Bronze Medal"
    • 从名次第 4 到第 n 的运动员,只能获得他们的名次编号(即,名次第 x 的运动员获得编号 "x")。

    使用长度为 n 的数组 answer 返回获奖,其中 answer[i] 是第 i 位运动员的获奖情况。

     

    示例 1:

    输入:score = [5,4,3,2,1]
    输出:["Gold Medal","Silver Medal","Bronze Medal","4","5"]
    解释:名次为 [1st, 2nd, 3rd, 4th, 5th] 。

    示例 2:

    输入:score = [10,3,8,9,4]
    输出:["Gold Medal","5","Bronze Medal","Silver Medal","4"]
    解释:名次为 [1st, 5th, 3rd, 2nd, 4th] 。
    

     

    提示:

    • n == score.length
    • 1 <= n <= 104
    • 0 <= score[i] <= 106
    • score 中的所有值 互不相同
    Related Topics
    • 数组
    • 排序
    • 堆(优先队列)

     

    • 👍 180
    • 👎 0

    优先队列

    解题思路

    此处撰写解题思路

    代码

    class Solution {
        public String[] findRelativeRanks(int[] score) {
            PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    return o2[0] - o1[0];
                }
            });
            for (int i = 0; i < score.length; i++) {
                queue.add(new int[]{score[i],i});
            }
            String[] arr = new String[score.length];
            String[] top = new String[]{"Gold Medal","Silver Medal","Bronze Medal"};
            int i = -1;
            while (!queue.isEmpty()){
                int[] cur = queue.poll();
                if (++i < top.length){
                    arr[cur[1]] = top[i];
                }else{
                    arr[cur[1]] = (i + 1) + "";
                }
            }
            return arr;
        }
    }

    LeetCode刷题【1392】最长快乐前缀

    「快乐前缀」 是在原字符串中既是 非空 前缀也是后缀(不包括原字符串自身)的字符串。

    给你一个字符串 s,请你返回它的 最长快乐前缀。如果不存在满足题意的前缀,则返回一个空字符串 "" 。

     

    示例 1:

    输入:s = "level"
    输出:"l"
    解释:不包括 s 自己,一共有 4 个前缀("l", "le", "lev", "leve")和 4 个后缀("l", "el", "vel", "evel")。最长的既是前缀也是后缀的字符串是 "l" 。
    

    示例 2:

    输入:s = "ababab"
    输出:"abab"
    解释:"abab" 是最长的既是前缀也是后缀的字符串。题目允许前后缀在原字符串中重叠。
    

     

    提示:

    • 1 <= s.length <= 105
    • s 只含有小写英文字母
    Related Topics
    • 字符串
    • 字符串匹配
    • 哈希函数
    • 滚动哈希

  • 👍 94
  • 👎 0
  • KMP模式串预处理方法
    其实就是KMP算法中模式串(Pattern)的预处理算法

    整个过程也可以当做是一个动态规划的算法过程来理解,其本质是状态机,额,这块就涉及知识盲区了,大学的知识早就忘记了。

    还是回到动态规划的话题来说吧,比较好理解点

    借用一个案例模式串来讲解下

    A B A C D A B A B C

    我们需要定义的DP数组的含义是,从下标0开始到当前字符结束的子串中,最长的前缀和结尾相同的子串的结束下标,感觉非常绕不像人话。

    以上面的子串A B A C D A B A为例,我们解释一下,这部分内容的 前缀和结尾相同的最长部分为A B A

    他在头部的结束下标为 2 ,对应为第二个A 字符所以对应的这部分为dp[7] = 2,或者简单理解为该子串的长度-1

    对于前面没有匹配的部分,我们用-1来表示,这样我们可以直接先目测得到上面案例字符串算出来的dp[]数组为

     A   B   A   C   D   A   B   A   B   C
    -1  -1   0  -1  -1   0   1   2   1  -1

    根据上面的结果我们可以看到,dp[i]的值依赖于 pattern[i]pattern[dp[i-1]+1]的匹配情况

    如果能匹配则dp[i] = dp[i-1] + 1

    不能匹配的话则继续与pattern[dp[dp[i-1]]+1]匹配,不能的话则继续再往前查找

    照旧拿上面的案例举个栗子

                         A   B   A   C   D   A   B   A   B
                        -1  -1   0  -1
    
     A   B   A   C   D   A   B   A   B
                         0   1   2   ↑

    箭头部分的B与前缀的C未能匹配,所以继续前移,找到前面的字符Adp[7] = 2的值作为下标的时候dp[2] = 0的情况下,如下

                                 A   B   A   C   D   A   B   A   B
                                -1  -1   0  -1
    
     A   B   A   C   D   A   B   A   B
                         0   1   2   ↑

    发现能匹配完成,则最终得到对应的dp[8] = dp[2] + 1 = 1

    最终我们可以知道数组末尾的值就是题目要求的最长快乐前缀的结束字符下标,在KMP中一般用next[]数组表示,而不是写成dp[]数组

    代码

    class Solution {
        public String longestPrefix(String s) {
            int[] next = getNextArr(s.toCharArray());
            int last = next[next.length - 1];
            if (last == -1) return "";
            return s.substring(0, last + 1);
        }
        private int[] getNextArr(char[] arr) {
            int[] next = new int[arr.length];
            Arrays.fill(next, -1);
            int idx = 0;
            int p = -1;
            while (++idx < arr.length){
                while ( p != -1 && arr[p+1] != arr[idx]){
                    p = next[p];
                }
                if (arr[p+1] == arr[idx]){
                    p++;
                }
                next[idx] = p;
            }
            return next;
        }
    }

    LeetCode刷题【19】删除链表的倒数第 N 个结点

    给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

     

    示例 1:

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

    示例 2:

    输入:head = [1], n = 1
    输出:[]
    

    示例 3:

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

     

    提示:

    • 链表中结点的数目为 sz
    • 1 <= sz <= 30
    • 0 <= Node.val <= 100
    • 1 <= n <= sz

     

    进阶:你能尝试使用一趟扫描实现吗?

    Related Topics
    • 链表
    • 双指针

  • 👍 2102
  • 👎 0
  • 双指针

    1. 定义俩指针,右指针先往后跑N位,之后一起往后跑,当右指针到结尾的时候左边那个指针就是要删除的节点
    2. 因为要删除的是左边这个节点,所以可以先把右指针往右再多移动一位,再和左指针一起往后跑,停下来的时候,左指针的next指向到next的next
    3. 如果第一开始先跑N位的时候,已经跑到了结尾,则说明要删除的是头结点,直接返回头结点的next
    4. 本题不支持输入的n大于链表长度的情况
    class Solution {
        public ListNode removeNthFromEnd(ListNode head, int n) {
            ListNode curN = head;
            while (--n >= 0 && curN != null){
                curN = curN.next;
            }
            if (curN==null){
                return head.next;
            }
            ListNode cur = head;
            curN = curN.next;
            while (curN != null){
                cur = cur.next;
                curN = curN.next;
            }
            cur.next = cur.next.next;
            return head;
        }
    }

    LeetCode刷题【1446】连续字符

    给你一个字符串 s ,字符串的「能量」定义为:只包含一种字符的最长非空子字符串的长度。

    请你返回字符串 s能量

     

    示例 1:

    输入:s = "leetcode"
    输出:2
    解释:子字符串 "ee" 长度为 2 ,只包含字符 'e' 。
    

    示例 2:

    输入:s = "abbcccddddeeeeedcba"
    输出:5
    解释:子字符串 "eeeee" 长度为 5 ,只包含字符 'e' 。
    

     

    提示:

    • 1 <= s.length <= 500
    • s 只包含小写英文字母。
    Related Topics
    • 字符串

  • 👍 102
  • 👎 0
  • 双指针,简单步骤分析理解
    双指针,简单题

    1. 右指针往后一直找到和当前字符不一样的那个字符,得到了当前字符的连续长度
    2. 对比已有的max长度值,取较大的那个
    3. 左指针直接移动到右指针当前位置,也就是下一个新字符的连续区间起点,再继续移动右指针,重复步骤(1)
    4. 直到到达字符串结束位置

    代码

    class Solution {
        public int maxPower(String s) {
            if (s.length() == 0) return 0;
            int max = 1;
            int left = 0;
            int right = 0;
            while (left < s.length()){
                while (++right < s.length() && s.charAt(right) == s.charAt(right-1)){}
                max = Math.max(max,right - left);
                left = right;
            }
            return max;
        }
    }