Leetcode刷题 2021.02.19

Leetcode1577 数的平方等于两数乘积的方法数

给你两个整数数组 nums1 和 nums2 ,请你返回根据以下规则形成的三元组的数目(类型 1 和类型 2 ):

类型 1:三元组 (i, j, k) ,如果 nums1[i]2 == nums2[j] * nums2[k] 其中 0 <= i < nums1.length 且 0 <= j < k < nums2.length
类型 2:三元组 (i, j, k) ,如果 nums2[i]2 == nums1[j] * nums1[k] 其中 0 <= i < nums2.length 且 0 <= j < k < nums1.length

题解里好多都是hash表解法,写了一会儿发现比较复杂。然后想想好像就是三数之和,于是用排序做了。代码的话基本就是三数之和那一套,分析的时间复杂度比较低。但是实际击败双百,应该是hash表的查找速度比较慢吧。

class Solution {
    int res = 0;
    public int numTriplets(int[] nums1, int[] nums2) {
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        helper(nums1, nums2);
        helper(nums2, nums1);
        return res;
    }

    private void helper(int[] nums1, int[] nums2){
        for(int k = 0; k < nums1.length; k++){
        	//先求下平方
            long target = (long)nums1[k] * nums1[k];
            int i = 0, j = nums2.length - 1;
            while (i < j){
            	//双指针从头和从尾找
                long temp = (long)nums2[i] * nums2[j];			
                //如果大于就减小右指针
                if (temp > target){
                    j--;
                //小于增大左指针   
                }else if (temp < target){
                    i++;
                }else{
                //如果是相等的情况,要特殊处理
                    if (nums2[i] == nums2[j]){
                        int count = j - i;
                        res += (1 + count) * count / 2;
                        break;
                    }
                    //否则找一下联系相同的个数
                    int n1 = 1, n2 = 1;
                    while (nums2[i] == nums2[i + 1]){
                        i++;
                        n1++;
                    }
                    while (nums2[j] == nums2[j - 1]){
                        j--;
                        n2++;
                    }
                    res += n1 * n2;
                    i++;
                    j--;
                }
            }
        }
    }
}

Leetcode1626 无矛盾的最佳球队

假设你是球队的经理。对于即将到来的锦标赛,你想组合一支总体得分最高的球队。球队的得分是球队中所有球员的分数 总和 。

然而,球队中的矛盾会限制球员的发挥,所以必须选出一支 没有矛盾 的球队。如果一名年龄较小球员的分数 严格大于 一名年龄较大的球员,则存在矛盾。同龄球员之间不会发生矛盾。

给你两个列表 scores 和 ages,其中每组 scores[i] 和 ages[i] 表示第 i 名球员的分数和年龄。请你返回 所有可能的无矛盾球队中得分最高那支的分数 。

先进行排序,然后在选择。因为是否要选择某一个人是不确定的,因此自然想到动态规划。实际上类似于最长上升子序列的题。

class Solution {
    public int bestTeamScore(int[] scores, int[] ages) {
        int n = scores.length;
        int[][] help = new int[n][2];
        for(int i = 0; i < n; i++){
            help[i][0] = ages[i];
            help[i][1] = scores[i];
        }
        //先用一个辅助数组进行排序,首先对年龄排序,然后对分数排序,这样就不用考虑是否会有矛盾的情况了
        Arrays.sort(help, (x, y) -> (x[0] == y[0] ? x[1] - y[1] : x[0] - y[0]));
        int[] dp = new int[n];
        dp[0] = help[0][1];
        int max = 0;
        //然后dp,基本类似于最长上升子序列
        for(int i = 0; i < n; i++){
            dp[i] = help[i][1];
            for(int j = 0; j < i; j++){
                if (help[i][1] >= help[j][1]){
                    dp[i] = Math.max(dp[i], dp[j] + help[i][1]);
                }
            }
             max = Math.max(max, dp[i]);
        }
        return max;
    }
}

Leetcode1670 设计前中后队列

请你设计一个队列,支持在前,中,后三个位置的 push 和 pop 操作。

请你完成 FrontMiddleBack 类:

FrontMiddleBack() 初始化队列。
void pushFront(int val) 将 val 添加到队列的 最前面 。
void pushMiddle(int val) 将 val 添加到队列的 正中间 。
void pushBack(int val) 将 val 添加到队里的 最后面 。
int popFront() 将 最前面 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1 。
int popMiddle() 将 正中间 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1 。
int popBack() 将 最后面 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1 。
请注意当有 两个 中间位置的时候,选择靠前面的位置进行操作。比方说:

将 6 添加到 [1, 2, 3, 4, 5] 的中间位置,结果数组为 [1, 2, 6, 3, 4, 5] 。
从 [1, 2, 3, 4, 5, 6] 的中间位置弹出元素,返回 3 ,数组变为 [1, 2, 4, 5, 6] 。

看到这题想到了数据流中的中位数那道题,想法也差不多,用两个双向队列进行模拟。保证某一个队列只比另一个队列最多多一个元素就行了。

class FrontMiddleBackQueue {
    LinkedList<Integer> front;
    LinkedList<Integer> back;
    int first;
    int second;

    public FrontMiddleBackQueue() {
        front = new LinkedList<>();
        back = new LinkedList<>();
    }
    
    public void pushFront(int val) {
        front.addFirst(val);
        first++;
        balance();
    }
    
    public void pushMiddle(int val) {
        if (first == second){
            back.addFirst(val);
            second++;
        }else{
            front.addLast(val);
            first++;
        }
    }
    
    public void pushBack(int val) {
        back.addLast(val);
        second++;
        balance();
    }
    
    public int popFront() {
        if (!front.isEmpty()){
            int temp = front.removeFirst();
            first--;
            balance();
            return temp;
        }else if (!back.isEmpty()){
            int temp = back.removeFirst();
            second--;
            balance();
            return temp;
        }
        return -1;
    }
    
    public int popMiddle() {
        if (first == 0 && second == 0) return -1;
        if (first == second){
            int temp = front.removeLast();
            first--;
            balance();
            return temp;
        }else{
            int temp = back.removeFirst();
            second--;
            balance();
            return temp;
        }
    }
    
    public int popBack() {
        if (!back.isEmpty()){
            int temp = back.removeLast();
            second--;
            balance();
            return temp;
        }
        return -1;
    }
	//balance用来调整队列里的元素数量。
    private void balance(){
        if (first > second){
            back.addFirst(front.removeLast());
            first--;
            second++;
        }
        if (second > first + 1){
            front.addLast(back.removeFirst());
            second--;
            first++;
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值