LeetCode 1616. 分割两个字符串得到回文串

1616. 分割两个字符串得到回文串

给你两个字符串 a 和 b ,它们长度相同。请你选择一个下标,将两个字符串都在 相同的下标 分割开。由 a 可以得到两个字符串: aprefix 和 asuffix ,满足 a = aprefix + asuffix ,同理,由 b 可以得到两个字符串 bprefix 和 bsuffix ,满足 b = bprefix + bsuffix 。请你判断 aprefix + bsuffix 或者 bprefix + asuffix 能否构成回文串。

当你将一个字符串 s 分割成 sprefix 和 ssuffix 时, ssuffix 或者 sprefix 可以为空。比方说, s = “abc” 那么 “” + “abc” , “a” + “bc” , “ab” + “c” 和 “abc” + “” 都是合法分割。

如果 能构成回文字符串 ,那么请返回 true,否则返回 false 。

注意, x + y 表示连接字符串 x 和 y 。

示例 1:
输入:a = “x”, b = “y”
输出:true
解释:如果 a 或者 b 是回文串,那么答案一定为 true ,因为你可以如下分割:
aprefix = “”, asuffix = “x”
bprefix = “”, bsuffix = “y”
那么 aprefix + bsuffix = “” + “y” = “y” 是回文串。

class Solution {
    public boolean checkPalindromeFormation(String a, String b) {
        return check(a, b) || check(b, a);
    }

    // 判断四种情况:a, b, ap+bs, bp+as
    private boolean check(String a, String b) {
        int i = 0, j = a.length() - 1;
        while (i < j && a.charAt(i) == b.charAt(j)) { // 前后缀尽可能匹配
            i++;
            j--;
        }
        if (i >= j) { // 判断 a, b 回文 无需分割
            return true;
        }
        return isPalindrome(a, i, j) || isPalindrome(b, i, j); // 判断 aP+bS, bP+aS
    }

    // ap+bs-> (a 前缀 + 判断中间的串是否回文 + b 后缀)
    // 判断剩下的a[idx:len-idx] 或 b[idx:len-idx], 如果是回文串加上对应的aP和bS则可得到完整结果
    private boolean isPalindrome(String s, int i, int j) {
        while (i < j && s.charAt(i) == s.charAt(j)) {
            i++;
            j--;
        }
        return i >= j;
    }
}

2389. 和有限的最长子序列

给你一个长度为 n 的整数数组 nums ,和一个长度为 m 的整数数组 queries 。

返回一个长度为 m 的数组 answer ,其中 answer[i] 是 nums 中 元素之和小于等于 queries[i] 的 子序列 的 最大 长度 。

子序列 是由一个数组删除某些元素(也可以不删除)但不改变剩余元素顺序得到的一个数组。

示例 1:
输入:nums = [4,5,2,1], queries = [3,10,21]
输出:[2,3,4]
解释:queries 对应的 answer 如下:

  • 子序列 [2,1] 的和小于或等于 3 。可以证明满足题目要求的子序列的最大长度是 2 ,所以 answer[0] = 2 。
  • 子序列 [4,5,1] 的和小于或等于 10 。可以证明满足题目要求的子序列的最大长度是 3 ,所以 answer[1] = 3 。
  • 子序列 [4,5,2,1] 的和小于或等于 21 。可以证明满足题目要求的子序列的最大长度是 4 ,所以 answer[2] = 4 。
class Solution {
    //  2、排序 前缀和 二分查找
    public int[] answerQueries(int[] nums, int[] queries) {
        Arrays.sort(nums);
        for (int i = 1; i < nums.length; i++) { // nums 原地求前缀和
            nums[i] += nums[i - 1];
        }
        int[] answer = new int[queries.length];
        for (int i = 0; i <  queries.length; i++) { // queries 遍历二分查找小于等于位置
            answer[i] = binarySearch(nums, queries[i]);
        }
        return answer;
    }

    public static int binarySearch(int[] nums, int n) {
        int l = 0, r = nums.length;
        while (l < r) {
            int mid = (l +  r) >> 1;
            if (nums[mid] <= n) {
                l = mid + 1; // 下标从 0 开始,大于queries[i]的自序列个数
            } else {
                r = mid;
            }
        }
        return l;
    }


    // 1、暴力查找
    public int[] answerQueries1(int[] nums, int[] queries) {
        Arrays.sort(nums);
        int[] answer = new int[queries.length];
        for (int i = 0; i < queries.length; i++) {
            int sum = 0;
            for (int j = 0; j < nums.length; j++) {
                sum += nums[j];
                if (sum <=  queries[i]) {
                    answer[i]++;
                }
            }
        }
        return answer;
    }
}

1957. 删除字符使字符串变好

一个字符串如果没有 三个连续 相同字符,那么它就是一个 好字符串 。

给你一个字符串 s ,请你从 s 删除 最少 的字符,使它变成一个 好字符串 。

请你返回删除后的字符串。题目数据保证答案总是 唯一的 。

示例 1:
输入:s = “leeetcode”
输出:“leetcode”
解释:
从第一组 ‘e’ 里面删除一个 ‘e’ ,得到 “leetcode” 。
没有连续三个相同字符,所以返回 “leetcode” 。

class Solution {
    public String makeFancyString(String s) {
        StringBuilder stringBuilder = new StringBuilder();
        for (char c : s.toCharArray()) {
            // stringBuilder 大于2个开始比较
            int len = stringBuilder.length();
            if (len >= 2 && stringBuilder.charAt(len - 1) == c && stringBuilder.charAt(len - 2) == c) { // 当前字符与前两个字符相同
                continue;
            }
            stringBuilder.append(c);
        }
        return stringBuilder.toString();
    }
}

2383. 赢得比赛需要的最少训练时长

你正在参加一场比赛,给你两个 正 整数 initialEnergy 和 initialExperience 分别表示你的初始精力和初始经验。

另给你两个下标从 0 开始的整数数组 energy 和 experience,长度均为 n 。

你将会 依次 对上 n 个对手。第 i 个对手的精力和经验分别用 energy[i] 和 experience[i] 表示。当你对上对手时,需要在经验和精力上都 严格 超过对手才能击败他们,然后在可能的情况下继续对上下一个对手。

击败第 i 个对手会使你的经验 增加 experience[i],但会将你的精力 减少 energy[i] 。

在开始比赛前,你可以训练几个小时。每训练一个小时,你可以选择将增加经验增加 1 或者 将精力增加 1 。

返回击败全部 n 个对手需要训练的 最少 小时数目。

示例 1:
输入:initialEnergy = 5, initialExperience = 3, energy = [1,4,3,2], experience = [2,6,3,1]
输出:8
解释:在 6 小时训练后,你可以将精力提高到 11 ,并且再训练 2 个小时将经验提高到 5 。
按以下顺序与对手比赛:

  • 你的精力与经验都超过第 0 个对手,所以获胜。
    精力变为:11 - 1 = 10 ,经验变为:5 + 2 = 7 。
  • 你的精力与经验都超过第 1 个对手,所以获胜。
    精力变为:10 - 4 = 6 ,经验变为:7 + 6 = 13 。
  • 你的精力与经验都超过第 2 个对手,所以获胜。
    精力变为:6 - 3 = 3 ,经验变为:13 + 3 = 16 。
  • 你的精力与经验都超过第 3 个对手,所以获胜。
    精力变为:3 - 2 = 1 ,经验变为:16 + 1 = 17 。
    在比赛前进行了 8 小时训练,所以返回 8 。
    可以证明不存在更小的答案。
class Solution {
    public int minNumberOfHours(int initialEnergy, int initialExperience, int[] energy, int[] experience) {
        int res = 0;
        for (int i = 0; i < energy.length; i++) {
            if (initialEnergy <= energy[i]) {
                res += energy[i] - initialEnergy + 1; // 训练至比对手多 1
                initialEnergy = energy[i] + 1;
            }
            if (initialExperience <= experience[i]) {
                res += experience[i] - initialExperience + 1; //
                initialExperience = experience[i] + 1;
            }
            initialEnergy -= energy[i];
            initialExperience += experience[i];
        }
        return res;
    } 
}

2089. 找出数组排序后的目标下标

给你一个下标从 0 开始的整数数组 nums 以及一个目标元素 target 。

目标下标 是一个满足 nums[i] == target 的下标 i 。

将 nums 按 非递减 顺序排序后,返回由 nums 中目标下标组成的列表。如果不存在目标下标,返回一个 空 列表。返回的列表必须按 递增 顺序排列。

示例 1:
输入:nums = [1,2,5,2,3], target = 2
输出:[1,2]
解释:排序后,nums 变为 [1,2,2,3,5] 。
满足 nums[i] == 2 的下标是 1 和 2 。

class Solution {
    // 排序 遍历 数值等于 target 的元素的下标
    public List<Integer> targetIndices1(int[] nums, int target) {
        Arrays.sort(nums);
        List<Integer> list = new ArrayList();
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == target) {
                list.add(i);
            }
        }
        return list;
    }

    // 二分查找 等于 target的下标
    // 在排序后数组中,这些数值等于 target 的元素的下标(如果存在)一定是连续的。寻找目标下标的左边界和目标下标的数量来构造目标下标数组
    // 目标下标即为的 [cnt1, cnt1 + cnt2) 左闭右开区间内的所有整数
    public List<Integer> targetIndices(int[] nums, int target) {
        int cnt1 = 0; // 小于 target 的数量
        int cnt2 = 0; // 等于 target 的数量
        for (int n : nums) {
            if (n < target) {
                cnt1++;
            } else if (n == target) {
                cnt2++;
            }
        }
        List<Integer> list = new ArrayList<>();
        for (int i = cnt1; i < cnt1 + cnt2; i++) {
            list.add(i); // 加入区间的整数
        }
        return list;
    }
}

2325. 解密消息

给你字符串 key 和 message ,分别表示一个加密密钥和一段加密消息。解密 message 的步骤如下:

使用 key 中 26 个英文小写字母第一次出现的顺序作为替换表中的字母 顺序 。
将替换表与普通英文字母表对齐,形成对照表。
按照对照表 替换 message 中的每个字母。
空格 ’ ’ 保持不变。
例如,key = “happy boy”(实际的加密密钥会包含字母表中每个字母 至少一次),据此,可以得到部分对照表(‘h’ -> ‘a’、‘a’ -> ‘b’、‘p’ -> ‘c’、‘y’ -> ‘d’、‘b’ -> ‘e’、‘o’ -> ‘f’)。
返回解密后的消息。

示例 1:
LeetCode 1616. 分割两个字符串得到回文串_第1张图片
输入:key = “the quick brown fox jumps over the lazy dog”, message = “vkbs bs t suepuv”
输出:“this is a secret”
解释:对照表如上图所示。
提取 “the quick brown fox jumps over the lazy dog” 中每个字母的首次出现可以得到替换表。

示例 2:
LeetCode 1616. 分割两个字符串得到回文串_第2张图片

输入:key = “eljuxhpwnyrdgtqkviszcfmabo”, message = “zwx hnfx lqantp mnoeius ycgk vcnjrdb”
输出:“the five boxing wizards jump quickly”
解释:对照表如上图所示。
提取 “eljuxhpwnyrdgtqkviszcfmabo” 中每个字母的首次出现可以得到替换表。

提示:
26 <= key.length <= 2000
key 由小写英文字母及 ’ ’ 组成
key 包含英文字母表中每个字符(‘a’ 到 ‘z’)至少一次
1 <= message.length <= 2000
message 由小写英文字母和 ’ ’ 组成

class Solution {
    public static String decodeMessage(String key, String message) {
        char cur = 'a';
        HashMap<Character, Character> map = new HashMap<>(); // 26 英文字母与 key 的对照
        for (int i = 0; i < key.length(); i++) {
            char c = key.charAt(i);
            if (c != ' ' && !map.containsKey(c)) { // key 中 a-z 可能出现多次,保存第一次出现的位置
                map.put(c, cur++);
            }
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < message.length(); i++) {
            char c = message.charAt(i);
            if (c != ' ') { // 根据 map 替换 message,空格 ' ' 保持不变
                c = map.get(c);
            }
            stringBuilder.append(c);
        }
        return stringBuilder.toString();
    }
}

你可能感兴趣的:(LeetCode,leetcode,算法,java,哈希表,字符串)