每日一练<2>

每日一练

大家好呀!我是小笙,接下来分享下10月份每日一题的解题思路~

870. 优势洗牌

给定两个大小相等的数组 nums1 和 nums2,nums1 相对于 nums2 的优势可以用满足 nums1[i] > nums2[i] 的索引 i 的数目来描述 ; 返回 nums1 的任意排列,使其相对于 nums2 的优势最大化

示例 :

输入:nums1 = [2,7,11,15], nums2 = [1,10,4,11]
输出:[2,11,7,15]

解读:两个长度相同的数组,使相同的索引下数组1的值排序后尽可能大于数组2的值

class Solution {
    public int[] advantageCount(int[] nums1, int[] nums2) {
        int len = nums1.length;
        if(len == 1){
            return nums1;
        }

        int[] res = new int[len];
        Integer[] idx2 = new Integer[len];
        for (int i = 0; i < len; ++i) {
            idx2[i] = i;
            res[i] = -1;
        }
        
        Arrays.sort(idx2, (i, j) -> nums2[i] - nums2[j]);
        Arrays.sort(nums1);
        Arrays.sort(nums2);

        int index = 0;
        for(int i=0;i<len;i++){
            if(nums1[i] > nums2[index]){
                res[idx2[index++]] = nums1[i];
                nums1[i] = -1;
            }
        }
        index = 0;
        for(int i=0;i<len;i++){
            if(res[i] == -1){
                while(nums1[index++] == -1);
                res[i] = nums1[index+-1];
            }
        }
        return res;
    }
}

856. 括号的分数

给定一个平衡括号字符串 S,按下述规则计算该字符串的分数:

  • () 1分
  • ()() 1+1分
  • (()) 1*2分

示例 :

输入: "()()"
输出: 2
----------------
输入: "(()(()))"
输出: 6

分治思想(递归方式)

class Solution {
    public int scoreOfParentheses(String s) {
        int len = s.length();
        if (len == 2) {
            return 1;
        }
        // 找到第一个累加的分界点
        int sum = 0,split = 0;
        for(int i=0;i<len;i++){
            sum += s.charAt(i) == '('?1:-1;
            if(sum == 0){
                split = i+1;
                break;
            }
        }

        // 不需要累加,类似这种情况((()))
        if(len == split){
            return 2 * scoreOfParentheses(s.substring(1,split-1));
        // 需要累加,类似这种情况()()()
        }else{
            return scoreOfParentheses(s.substring(0,split)) +  scoreOfParentheses(s.substring(split));
        }
    }
}

1790. 仅执行一次字符串交换能否使两个字符串相等

给你长度相等的两个字符串 s1 和 s2 。一次 字符串交换操作的步骤如下:选出某个字符串中的两个下标(不必不同),并交换这两个下标所对应的字符。如果对 其中一个字符串执行最多一次字符串交换就可以使两个字符串相等,返回 true ;否则,返回 false

示例

输入:s1 = "bank", s2 = "kanb"
输出:true
解释:例如,交换 s2 中的第一个和最后一个字符可以得到 "bank"
-----------------------------------------------------
输入:s1 = "attack", s2 = "defend"
输出:false
解释:一次字符串交换无法使两个字符串相等

解题思路:分两种情况:1.字符串相同 2.字符串不相同但是可以通过一次交换使得两个字符串相同

class Solution {
    public boolean areAlmostEqual(String s1, String s2) {
        // 判断字符串是否相同
        if(s1.equals(s2)){
            return true;
        }
        // 通过index1,index2 分别记录不同字符的下标
        int index1 = -1,index2 = -1;
        for(int i=0;i<s1.length();i++){
            if(s1.charAt(i) != s2.charAt(i)){
                if(index1 == -1){
                    index1 = i;
                }else if(index2 == -1){
                    index2 = i;
                }else{
                     // 如果上述情况都没满足,说明出现了第三个字符不相同的情况
                    return false;
                }
            }
        }
        // 排除 1.只有一个字符不同的情况 2.两个字符进行交换但是还是不相同的情况
        if(index1 == -1 || index2 == -1 || s2.charAt(index1) != s1.charAt(index2) || s2.charAt(index2) != s1.charAt(index1)){
            return false;
        }
        return true;
    }
}

817. 链表组件

给定链表头结点 head,该链表上的每个结点都有一个 唯一的整型值 。同时给定列表 nums,该列表是上述链表中整型值的一个子集。返回列表 nums 中组件的个数,这里对组件的定义为:链表中一段最长连续结点的值(该值必须在列表 nums 中)构成的集合

示例

输入: head = [0,1,2,3], nums = [0,1,3]
输出: 2
解释: 链表中,01 是相连接的,且 nums 中不包含 2,所以 [0, 1] 是 nums 的一个组件,同理 [3] 也是一个组件,故返回 2

解题思路:遍历链表 head ,寻找组件开始点是当前链表值存在于 nums 数组中,如果中断则再次寻找开始点,只要统计开始点则是组件个数

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public int numComponents(ListNode head, int[] nums) {
        List<Integer> list = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();
        while(head != null){
            list.add(head.val);
            head = head.next;
        }
        for(int i=0;i<nums.length;i++){
            list2.add(nums[i]);
        }
        int res = 0;
        for(int i=0;i<list.size();i++){
            int index = i;
           while(list2.contains(list.get(index++)) && index < list.size());
           if(list2.contains(list.get(i))){
                res++;
                i = index - 1;
           }
        }
        return res;
    }
}

优化代码,既然是存在问题,则使用 HashSet 代替 list 性能会更加好!

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public int numComponents(ListNode head, int[] nums) {
        Set<Integer> set = new HashSet<>();
        for(int i=0;i<nums.length;i++){
            set.add(nums[i]);
        }
        int res = 0;
        while(head != null){
            int temp = head.val;
            //寻找开始点
            while(head != null && set.contains(head.val)){
                head = head.next;
            }
            // 判断是否为开始点
            if(head == null || temp != head.val){
                res++;
            }else{
                head = head.next;
            }
        }
        return res;
    }
}

769. 最多能完成排序的块

给定一个长度为 n 的整数数组 arr ,它表示在 [0, n - 1] 范围内的整数的排列。我们将 arr 分割成若干 块 (即分区),并对每个块单独排序。将它们连接起来后,使得连接的结果和按升序排序后的原数组相同。返回数组能分成的最多块数量

例子

输入: arr = [4,3,2,1,0]
输出: 1
解释:
将数组分成2块或者更多块,都无法得到所需的结果。
例如,分成 [4, 3], [2, 1, 0] 的结果是 [3, 4, 0, 1, 2],这不是有序的数组
---------------------------------------------------------------------
输入: arr = [1,0,2,3,4]
输出: 4
解释:
我们可以把它分成两块,例如 [1, 0], [2, 3, 4]。
然而,分成 [1, 0], [2], [3], [4] 可以得到最多的块数

解题思路:最早能够分块的就分块,就比如在【1,5】区间肯定需要存在最小的5个数,就可以分块,按照这个思路来记录块数

class Solution {
    public int maxChunksToSorted(int[] arr) {
        int res = 0,index = 0;
        int[] temp = arr.clone();
        Arrays.sort(temp);
        Set<Integer> set = new HashSet<>();
        for(int i=0;i<arr.length;i++){
            set.add(arr[i]);
            while(index <= i && set.contains(temp[index])){
                index++;
            }
            if(index == i+1){
                res++;
            }
        }
        return res;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗念笙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值