首页 > 其他分享 >MarsCode青训营打卡Day5(2025年1月18日)|稀土掘金-148.小A的子数组权值、304.计算特定条件下的四元组数量

MarsCode青训营打卡Day5(2025年1月18日)|稀土掘金-148.小A的子数组权值、304.计算特定条件下的四元组数量

时间:2025-01-18 21:29:05浏览次数:3  
标签:key int 18 ++ 四元组 数组 权值 new 打卡

资源引用:

148.小A的子数组权值

304.计算特定条件下的四元组数量

今日小记:

148.题既可以如笔者给出的题解来遍历全部的子数组,也可以按照遍历权值的方式通过滑动窗口来实现,两种解题方法的时间复杂度相同,但前者的操作更为简单。

304.题与Day4的三元组一题有相似之处,均通过将多元组拆分成更小的元组再进行计算,从而简化了计算。

稀土掘金-148.小A的子数组权值(148.小A的子数组权值

题目分析:

给定一个长度为n的数组a,定义“权值”为一个连续子数组内不同元素的个数。

求该数组中权值为1,2,3...,n的连续子数组数量有多少个,通过输出一个包含n个整数的,第i个数表示权值为i的子数组个数的数组来作答。

解题重点:

由于题目限定了“连续子数组”的“连续”,故考虑用双指针实现的增广窗口来遍历所有连续子数组。

又因为需要知道连续子数组中不同元素的个数,因此我们可以为每个增广窗口配套一个哈希表以记录当前连续子数组所包含的不同元素,而keySet的长度就是该子数组的权值。

import java.util.Arrays;
import java.util.Set;
import java.util.HashSet;
public class Main {
    public static int[] solution(int n, int[] a) {
        int[] c = new int[n + 1];
        for (int left = 0; left < n; left++) {
            Set<Integer> set = new HashSet<>();
            for (int right = left; right < n; right++) {
                set.add(a[right]);
                c[set.size()]++;
            }
        }
        return Arrays.copyOfRange(c, 1, c.length);
    }

    public static void main(String[] args) {
        System.out.println(Arrays.equals(solution(4, new int[]{1, 2, 2, 3}), new int[]{5, 4, 1, 0}));
        System.out.println(Arrays.equals(solution(3, new int[]{1, 1, 1}), new int[]{6, 0, 0}));
        System.out.println(Arrays.equals(solution(5, new int[]{1, 2, 3, 2, 1}), new int[]{5, 5, 5, 0, 0}));
    }
}

稀土掘金-304.计算特定条件下的四元组数量(304.计算特定条件下的四元组数量

题目分析:

给定一个长度为n的数组a,要求计算有多少个四元组(i, j, k, l)满足以下条件:

  1. i < j < k < l
  2. a_i + a_j == a_k ^ a_l

此外,由于计算过程中的数可能非常大,需要对计算结果取10^9 + 7的模后输出结果。

解题重点:

该四元组由两部分构成,即相加的部分和异或的部分,故可分为两个二元组来考虑。

又因为计算过程中,使用元素值进行计算,对下标有相对关系的要求,我们可以考虑用哈希映射,将元素值和对应下标构造成键值对,分别将两个二元组的运算结果及下标存储到两个Map中。并且,由于在相加二元组中,i<j;在异或二元组中,k<l;两个二元组之间,只需满足j<k即可,故两个Map的键值对的值只需分别存储 j 和 k 即可。注意:由于不同的二元组的计算结果可能相同,故相同键可以有多个不同的值,用List存储

还需注意,在计算过程中时刻需要对 10^9 + 7取模(在实际计算中使用1000000007L表示),为防止数值溢出,计算过程中用长整型long做运算,最终转回int并返回。

解题思路:

  1. 构造HashMap<Long, List<Integer>> map1, map2。初始化返回值res
  2. 遍历数组a,将i < j的二元组(i, j)的元素和a_i + a_j (模后)作为键、j作为值,存储至map1
  3. 遍历数组a,将k < l的二元组(k, l)的元素和a_k ^ a_l (模后)作为键,k作为值,存储值map2
  4. 遍历map1的键key,在map2中查询是否存在key,若存在,判断 j < k是否成立,若成立,则res++。
  5. 最终返回res(模后)。
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;

public class Main {
    private static final long MOD = 1000000007L;

    public static int solution(int n, int[] a) {
        long res = 0;
        Map<Long, List<Integer>> map1 = new HashMap<>();
        Map<Long, List<Integer>> map2 = new HashMap<>();

        /*1.构造相加二元组的HashMap */
        for (int i = 0; i < a.length - 3; i++) {
            for (int j = i + 1; j < a.length - 2; j++) {
                long sum = (a[i] + a[j]) % MOD;
                map1.computeIfAbsent(sum, K -> new ArrayList<>()).add(j);
            }
        }

        /*2.构造异或二元组的HashMap */
        for (int k = 2; k < a.length; k++) {
            for (int l = k + 1; l < a.length; l++) {
                long xor = (a[k] ^ a[l]) % MOD;
                map2.computeIfAbsent(xor, K -> new ArrayList<>()).add(k);
            }
        }

        /*3.遍历map1的键,在map2中查询key,并比较二者的value,得到符合条件的四元组个数 */
        for (long key : map1.keySet()) {
            if (!map2.containsKey(key)) continue;

            List<Integer> list1 = map1.get(key);
            List<Integer> list2 = map2.get(key);
            for (int value1 : list1) {
                for (int value2 : list2) {
                    if (value1 < value2) res = (res + 1) % MOD;
                }
            }
        }

        return (int)res;
    }

    public static void main(String[] args) {
        System.out.println(solution(5, new int[]{2, 3, 1, 5, 4}) == 1);
        System.out.println(solution(6, new int[]{1, 2, 3, 4, 5, 6}) == 1);
        System.out.println(solution(4, new int[]{4, 1, 3, 2}) == 0);
    }
}

总结反思:

  1. 对1000000007L取模是一种常见的防溢出技巧
  2. 使用类接口实现的具体对象时,必须谨记ta是一个实体,ta作为参数时实际上使用的是ta的引用。在笔者原先的代码中,错误的将唯一的实例tmpList作为参数传递给map后,直接将其复用或清空,都导致了数据的丢失。
  3. map.computerIfAbsent的使用方式:在map中查询key是否存在,若存在返回其值,否则调用mappingFunction计算值。
V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)

标签:key,int,18,++,四元组,数组,权值,new,打卡
From: https://blog.csdn.net/csy031117/article/details/145225371

相关文章

  • 蓝桥杯单片机基础部分——5、DS18B20温度传感器
    前言好久没有更新关于蓝桥杯单片机相关的模块了,今天更新一下数字温度传感器DS18B20的相关应用单线数字温度计DS1820介绍DS1820数字温度计提供9位(二进制)温度读数,指示器件的温度。信息经过单线接口送入DS1820或从DS1820送出,因此从主机CPU到DSl820仅需一条线(和地线)......
  • 1.18
    A签到题,没啥可说的#include<iostream>#include<cstring>usingnamespacestd;constintN=110;intn,m;intx[N],y[N];voidsolve(){ memset(x,0,sizeof(x)); memset(y,0,sizeof(y)); for(inti=1;i<=n;i++){ cin>>x[i]>>......
  • 1.18
    HTML超链接的使用今日学习超链接文本链接使用一对标签格式:<href="目标URL"target="目标窗口">指针文本target属性_blank新窗口_self当前窗口_parent父窗口_top整个窗口框架名称......
  • [20250118]find命令文件统配符使用引号.txt
    [20250118]find命令文件统配符使用引号.txt--//网上看到的问题,实际上问题许多人包括我自己也经常会犯类似的错误。因为如果没有引号,bashshell会展开解释。--//通过一个简单例子说明问题:$mkdir202501$cd202501$toucha1.txt$toucha2.txt$echo*.txta1.txta2.txt$echo*......
  • Spread.NET 18.0 支持.NET9.0 Crack
    Spread.NET全球销量第一的C#.NET电子表格,包含500多个Excel函数在C#.NET中提供真正类似Excel的电子表格体验,且不依赖Excel。创建财务、预算/预测、科学、工程、医疗保健、保险、教育、制造和许多其他类似的业务应用程序。使用全面的API创建企业电子表格、高级网......
  • [ARC 188A] ABC Symmetry
    solutionbyXiangXunYi思路推导step1首先题目中操作二同时删掉A,B,C的条件相当于同时将三者数量减一,操作一删掉两个相同字符等同于将某一字符的数量减二,那么我们可以发现只使用操作一不会改变奇偶,操作二则是同时反转奇偶,所以一个字符串是个好字符串的必要条件是其中三个字母......
  • 2025.1.1-2025.1.18
    期末周这些天是期末周,考着考着有些科就出了成绩大学的期末考试更加应试,更加简单,要想取得好成绩完全可以靠期末周突击考试很显然,我没有应试的那个态度,复习的很潦草,没什么动力要想取得好绩点,我通过这次期末考试也得到了一些经验:1,往年的习题----很有可能再考2.平......
  • [2025.1.18 JavaSE学习]标准I/O流 && 转换流
    标准I/O流System.in:标准输入默认设备:键盘类型:InputStreamSystem.out:标准输出默认设备:显示器类型:PrintStreamSystem.in编译类型为InputStream,而运行类型为BufferedInputStreampublicfinalstaticInputStreamin=null;System.out编译类型为PrintStream,运行类......
  • 2025.1.18 JavaScript基础
    1、变量的定义var变量名例如:<html> <body> <scripttype="text/javascript"> functionzhaoling(){ n=Number(document.form1.txt1.value); if(n!=parseInt(n/1)||n<1||n>100) { alert("请输入一个1-100的整数"); ......
  • 2025-01-18:施咒的最大总伤害。用go语言,一个魔法师掌握了多种不同的咒语,每个咒语对应一
    2025-01-18:施咒的最大总伤害。用go语言,一个魔法师掌握了多种不同的咒语,每个咒语对应一个伤害值,这些伤害值存储在数组power中,其中可能会有多个咒语具有相同的伤害值。使用某个特定伤害值为power[i]的咒语后,魔法师不能再使用伤害值为power[i]-2、power[i]-1、power[i]+1......