2525.根据规则将箱子分类/并查集/动态规划

2525. 根据规则将箱子分类 - 力扣(LeetCode)

给你四个整数 lengthwidthheightmass ,分别表示一个箱子的三个维度和质量,请你返回一个表示箱子 类别 的字符串。

  • 如果满足以下条件,那么箱子是 "Bulky" 的:
    • 箱子 至少有一个 维度大于等于 104
    • 或者箱子的 体积 大于等于 109
  • 如果箱子的质量大于等于 100 ,那么箱子是 "Heavy" 的。
  • 如果箱子同时是 "Bulky""Heavy" ,那么返回类别为 "Both"
  • 如果箱子既不是 "Bulky" ,也不是 "Heavy" ,那么返回类别为 "Neither"
  • 如果箱子是 "Bulky" 但不是 "Heavy" ,那么返回类别为 "Bulky"
  • 如果箱子是 "Heavy" 但不是 "Bulky" ,那么返回类别为 "Heavy"

注意,箱子的体积等于箱子的长度、宽度和高度的乘积。

示例 1:

复制代码
输入:length = 1000, width = 35, height = 700, mass = 300
输出:"Heavy"
解释:
箱子没有任何维度大于等于 104 。
体积为 24500000 <= 109 。所以不能归类为 "Bulky" 。
但是质量 >= 100 ,所以箱子是 "Heavy" 的。
由于箱子不是 "Bulky" 但是是 "Heavy" ,所以我们返回 "Heavy" 。

示例 2:

复制代码
输入:length = 200, width = 50, height = 800, mass = 50
输出:"Neither"
解释:
箱子没有任何维度大于等于 104 。
体积为 8 * 106 <= 109 。所以不能归类为 "Bulky" 。
质量小于 100 ,所以不能归类为 "Heavy" 。
由于不属于上述两者任何一类,所以我们返回 "Neither" 。

提示:

  • 1 <= length, width, height <= 105
  • 1 <= mass <= 103

思路

用数学公式,然后进行判断,返回值

完整代码

java 复制代码
class Solution {
    public String categorizeBox(int length, int width, int height, int mass) {
        long maxd = Math.max(length, Math.max(width, height)), vol = 1L * length * width * height;
        boolean isBulky = maxd >= 10000 || vol >= 1000000000, isHeavy = mass >= 100;
        if (isBulky && isHeavy) {
             return "Both";
        } else if (isBulky) {
            return "Bulky";
        } else if (isHeavy) {
            return "Heavy";
        } else {
            return "Neither";
        }
    }
}

题目来源:【模板】并查集 - 洛谷

就是将要合并的数做成一个集合,然后再查找;

其实我觉得并查集好像最关键的就是找根节点,只要跟根节点扯上关系就能证明属于一个集合;

所以首先我先做了一个查找根节点的函数

java 复制代码
public static int find(int x,int p[])
{
    int x_root=x;
    while(p[x_root]!=-1)
    x_root = p[x_root];
    return x_root;

}

首先我会让所有数都指向自己,也就是我先都把他们的节点设为-1(因为题目中有说集合中的元素都是大于0的,就不用担心出现漏洞;然后就是用循环一步步往上找,知道找到根节点,然后返回根节点的值;

java 复制代码
public static void op(int x,int y,int p[])
{
    int x_root = x;
    int y_root = y;
    int find(int x,int p[]);
    x_root = find(x,p);
    y_root = find(y,p);
    if(x_root != y_root)
        p[x_root] = y_root ;
}

然后我又做了一个合并的函数,就是把有关系的集合合并起来,也是利用的根节点,先找到我要合并的集合的根节点,然后合并;

java 复制代码
class Text(){
     public static void main(Sting[]args)
{
    int m,n;
    int x,y,z,v;
    int find(int x,int p[]);
    scanf("%d %d",&m,&n);
    int p[m+1];
    for(int i=1;i<=m;i++)
        p[i]=-1;
}

然后在主函数中,将数据都输入,特别是将父节点数组全部初始化为-1。

cs 复制代码
  for(int i=0;i<n;i++)
    {
        scanf("%d %d %d",&x,&y,&z);
        if(x==1)
            op(y,z,p);
            if(x==2)
            {
                int y_root,z_root;
                y_root = find(y,p);
                z_root = find(z,p);
                if(y_root == z_root)
                    printf("Y\n");
                else
                    printf("N\n");
            }

    }
    return 0;
}

然后就是,判断是做集合还是找集合,如果是1就是做集合,如果是2就是找集合,然后按条件输出Y或者N;

(最后交上去出来的结果也不是很好,发现时间有点超限,应该是数据类型不对,或者说我要用路径压缩)

改错:

我知道为什么时间超限了,因为我没有按照把小的树往大的树上面凑,而是随便凑,那么这样就会导致树的深度变大,也就是说时间会变长,那么我只需要在我将集合合并的函数上加上一组判断的语句;

java 复制代码
public static void op(int x,int y,int p[],int rank[])
{
    int x_root = x;
    int y_root = y;
    int find(int x,int p[]);
    x_root = find(x,p);
    y_root = find(y,p);
    if(x_root != y_root)
        {
            if(rank[x_root] > rank[y_root])
               p[y_root]=x_root;
            else if(rank[x_root] < rank[y_root])
                p[x_root] = y_root;
            else
            {
                p[x_root] = y_root;
                rank[y_root]++;
            }
        }
}

rank[]数组就是树的高度,首先判断树的高度,然后将小的树往大的树上面扣,这样找的时候就能有效节省时间复杂度;

例题一(链接)

【模板】最长公共子序列

题目描述

给出 1,2,\\ldots,n 的两个排列 P_1P_2 ,求它们的最长公共子序列。

输入格式

第一行是一个数 n

接下来两行,每行为 n 个数,为自然数 1,2,\\ldots,n 的一个排列。

输出格式

一个数,即最长公共子序列的长度。

样例 #1

样例输入 #1

```

5

3 2 1 4 5

1 2 3 4 5

```

样例输出 #1

```

3

```

提示

  • 对于 50\\% 的数据, n \\le 10\^3

  • 对于 100\\% 的数据, n \\le 10\^5

思路

本来我用的是滚动数组来做,但是还是时间超限了,我猜测应该不能一组数据一组数据的更新,然后看题目中说是由相同的数字组成,那么就是说只是顺序不同,但元素是相同的,其实这个题就是LIS(参考文章),以一个串为模板串,然后判断另一个串在这个串里面的排列顺序;

代码

java 复制代码
class Text{

int inf = 100010l;

public static int min(int x,int y)
{
    return x<y?x:y;
}

public static void main(String[]args)
{
    
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int []p1 = new int[num];
    int []p2 = new int[num];
    int []dp = new int[num];
    int []map = new int[map];     //dp表示的是合乎题意的子串,map下标表示的是数值,而其对应的数字是该数值的位置;
    for(int i=1; i<=n; i++)
    {
        p1[i] = sc.nextInt();
        dp[i]=inf;            //初始化
        map[p1[i]]=i;         //明确一个串里面数字的顺序,以便之后另一个串的数字在这个串里面找位置
    }
    for(int i=1; i<=n; i++)
        scanf("%d",&p2[i]);

    int len=0;               //找到的合乎题目意思的子串长度
    dp[0]=0;                 
    for(int i=1; i<=n; i++)
    {
        int xx=0,r=len,mid;  
        
        if(map[p2[i]]>dp[len])  //如果说p2第i个数字在p1中的位置大于已有的子串的最后一个数字

            dp[++len]=map[p2[i]];  //那么就把这个数字加入子串中
        else
        {
            while(xx<r)   //二分查找(就是更加方便查找,节省时间)
            {
                mid=(xx+r)/2;
                if(map[p2[i]]<dp[mid])
                    r=mid;
                else
                    xx=mid+1;
            }
            dp[xx]=min(map[p2[i]],dp[xx]);
        }
    }

    printf("%d",len);  //len就是子串的长度
  
}

例题二(编辑距离 - 洛谷

# 编辑距离

题目描述

AB 是两个字符串。我们要用最少的字符操作次数,将字符串 A 转换为字符串 B。这里所说的字符操作共有三种:

  1. 删除 一个字符;

2.插入 一个字符;

  1. 将一个字符改为另一个字符。

A, B 均只包含小写字母。

输入格式

第一行为字符串 A;第二行为字符串 B;字符串 A, B 的长度均小于 2000

输出格式

只有一个正整数,为最少字符操作次数。

样例 #1

样例输入 #1

```

sfdqxbw

gfdgw

```

样例输出 #1

```

4

```

提示

对于 100 \\% 的数据,1 \\le \|A\|, \|B\| \\le 2000

思路

首先知道有俩个字符串,那么可以建一个二维数组arr[ i ][ j ],分别用于俩个字符串的遍历;

然后根据题目可以知道,对于每一个字符,具有四种操作,删除,插入,替换,不变;那么就可以判断在不同情况下,该怎么更新arr里面的值;

当新遍历的俩个字符相等时,就不要增加步骤,那么此时这个点的步骤就和没新遍历的那俩个字符时相等,即 :

arr[ i ][ j ] = arr[ i - 1 ][ j - 1 ];

当不满足这个条件的时候,就考虑此时该进行什么操作,arr[ i ][ j - 1 ]表示的是增加一个字符的操作, arr[ i - 1 ][ j ]表示的是删除一个字符的操作,arr[ i - 1 ][ j - 1 ]表示替换;

代码

复制代码
#include<stdio.h>
#include<string.h>
#define num 3010

int min(int x,int y)
{
    return x<y?x:y;
}

int main()
{
    char A[num],B[num];
    int arr[num][num];
    int a,b;
    scanf("%s%s",A,B);
    a=strlen(A);
    b=strlen(B);
    int c=a>b?a:b;
    for(int i=1;i<=c;i++)
    {
        arr[i][0]=i;
        arr[0][i]=i;
    }
    for(int i=1; i<=a; i++)
        for(int j=1; j<=b; j++)
        {
            if(A[i-1]==B[j-1])
            {
                arr[i][j]=arr[i-1][j-1];
                
            }
               else
            arr[i][j]=min(min(arr[i-1][j],arr[i][j-1]),arr[i-1][j-1])+1;
        }
    printf("%d",arr[a][b]);
    return 0;
}
相关推荐
Kay_Liang7 分钟前
大语言模型如何精准调用函数—— Function Calling 系统笔记
java·大数据·spring boot·笔记·ai·langchain·tools
自由的疯24 分钟前
Java 如何学习Docker
java·后端·架构
自由的疯25 分钟前
Java Docker本地部署
java·后端·架构
007php00727 分钟前
猿辅导Java面试真实经历与深度总结(二)
java·开发语言·python·计算机网络·面试·职场和发展·golang
摇滚侠30 分钟前
Spring Boot 3零基础教程,WEB 开发 内容协商机制 笔记34
java·spring boot·笔记·缓存
一勺菠萝丶30 分钟前
在 macOS 上用 Docker 为 Java 后端 & 常见开发需求搭建完整服务(详尽教程)
java·macos·docker
顾漂亮36 分钟前
JVM底层攻坚
java·jvm·spring
编程岁月37 分钟前
java面试-0215-HashMap有序吗?Comparable和Comparator区别?集合如何排序?
java·数据结构·面试
木井巳1 小时前
[Java数据结构与算法]详解排序算法
java·数据结构·算法·排序算法
没有bug.的程序员2 小时前
分布式架构未来趋势:从云原生到智能边缘的演进之路
java·分布式·微服务·云原生·架构·分布式系统