Page 12 of 61

LeetCode刷题【1816】截断句子

句子 是一个单词列表,列表中的单词之间用单个空格隔开,且不存在前导或尾随空格。每个单词仅由大小写英文字母组成(不含标点符号)。

  • 例如,"Hello World""HELLO""hello world hello world" 都是句子。

给你一个句子 s​​​​​​ 和一个整数 k​​​​​​ ,请你将 s​​ 截断 ​,​​​使截断后的句子仅含 k​​​​​​ 个单词。返回 截断 s​​​​​​ 后得到的句子

 

示例 1:

输入:s = "Hello how are you Contestant", k = 4
输出:"Hello how are you"
解释:
s 中的单词为 ["Hello", "how" "are", "you", "Contestant"]
前 4 个单词为 ["Hello", "how", "are", "you"]
因此,应当返回 "Hello how are you"

示例 2:

输入:s = "What is the solution to this problem", k = 4
输出:"What is the solution"
解释:
s 中的单词为 ["What", "is" "the", "solution", "to", "this", "problem"]
前 4 个单词为 ["What", "is", "the", "solution"]
因此,应当返回 "What is the solution"

示例 3:

输入:s = "chopper is not a tanuki", k = 5
输出:"chopper is not a tanuki"

 

提示:

  • 1 <= s.length <= 500
  • k 的取值范围是 [1,  s 中单词的数目]
  • s 仅由大小写英文字母和空格组成
  • s 中的单词之间由单个空格隔开
  • 不存在前导或尾随空格
Related Topics
  • 数组
  • 字符串

  • 👍 57
  • 👎 0
  • 空格判断、字符复制

    1. 简单,就复制字符
    2. 字符复制完了加一个空格
    3. 计数,小于k
    4. 最后会多复制一个空格最后要截掉

    代码

    class Solution {
        public String truncateSentence(String s, int k) {
            char[] arr = new char[501];
            int cnt = 0;
            int idx = 0;
            int arrIdx = -1;
            while (cnt < k && idx < s.length()){
                if (s.charAt(idx) == ' '){
                    idx++;
                    continue;
                }
                while (idx < s.length() && s.charAt(idx) != ' ' ){
                    arr[++arrIdx] = s.charAt(idx++);
                }
                arr[++arrIdx] = ' ';
                cnt++;
            }
            char[] arr2 = new char[arrIdx];
            System.arraycopy(arr,0,arr2,0,arrIdx);
            return new String(arr2);
        }
    }

    其实题目给了限制条件了

     1 <= s.length <= 500 
     k 的取值范围是 [1, s 中单词的数目] 
     s 仅由大小写英文字母和空格组成 
     s 中的单词之间由单个空格隔开 
     不存在前导或尾随空格 

    所以可以更简单点,直接判断遇到的空格的个数就可以了

    代码

    class Solution {
        public String truncateSentence(String s, int k) {
            char[] arr = s.toCharArray();
            int cnt = 0;
            int idx = -1;
            while (cnt < k && ++idx < s.length()){
                if (arr[idx] == ' '){
                    cnt++;
                }
            }
            char[] arr2 = new char[idx];
            System.arraycopy(arr,0,arr2,0,idx);
            return new String(arr2);
        }
    }

    LeetCode刷题【383】赎金信

    给你两个字符串:ransomNotemagazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

    如果可以,返回 true ;否则返回 false

    magazine 中的每个字符只能在 ransomNote 中使用一次。

     

    示例 1:

    输入:ransomNote = "a", magazine = "b"
    输出:false
    

    示例 2:

    输入:ransomNote = "aa", magazine = "ab"
    输出:false
    

    示例 3:

    输入:ransomNote = "aa", magazine = "aab"
    输出:true
    

     

    提示:

    • 1 <= ransomNote.length, magazine.length <= 105
    • ransomNotemagazine 由小写英文字母组成
    Related Topics
    • 哈希表
    • 字符串
    • 计数

  • 👍 363
  • 👎 0
  • 哈希统计

    class Solution {
        public boolean canConstruct(String ransomNote, String magazine) {
            int[] arr = new int[26];
            for (int i = 0; i < magazine.length(); i++) {
                arr[magazine.charAt(i)-'a']++;
            }
            for (int i = 0; i < ransomNote.length(); i++) {
                arr[ransomNote.charAt(i)-'a']--;
                if (arr[ransomNote.charAt(i)-'a'] < 0 ){
                    return false;
                }
            }
            return true;
        }
    }

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