RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1575610
Accepted
Kiawem
Kiawem
Asked:2024-04-11 03:33:10 +0000 UTC2024-04-11 03:33:10 +0000 UTC 2024-04-11 03:33:10 +0000 UTC

加快算法速度以达到 1 秒

  • 772

我正在解决一个问题,我的问题是在某个测试中出现TL(时间限制)错误(代码在条件之后呈现),我不知道如何加速算法以便测试通过,也许我的逻辑有问题——我无法否认这一点。

问题条件:给定两个数组a和b,长度为N,由整数组成。考虑一个由连接点 (0, ai) 和 (1, bi) 的线段组成的集合,其中 1 <= i <= N。找出该集合中不与其他线段相交的线段的数量。 例子

相交是指至少有一个公共点的线段,即具有相同端点的线段相交。

输入格式

在第一行中输入 N (1 <= N <= 3 * 10^5) - 段数。接下来,N 行包含由空格 ai 和 bi 分隔的 2 个整数(1 <= ai, bi <= 2 * N),指定第 i 段的坐标。保证输入中指定的所有段都不同,即对于 i != j,至少满足条件 ai != aj 和 bi != bj 之一

代码:

import java.util.*;


public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        Map<Integer, ArrayList<Integer>> nums = new HashMap<>();
        int amount = sc.nextInt();
        sc.nextLine();
        for (int i = 0; i < amount; i++) {
            String[] point = sc.nextLine().split(" ");
            int x = Integer.parseInt(point[0]);
            int y = Integer.parseInt(point[1]);
            if (!nums.containsKey(x)) {
                nums.put(x, new ArrayList<>());
            }
            nums.get(x).add(y);
        }

        int count = 0;
        for (int key1 : nums.keySet()) {
            boolean intersects = false;
            ArrayList<Integer> values1 = nums.get(key1);
            for (int key2 : nums.keySet()) {
                if (key1 != key2) {
                    ArrayList<Integer> values2 = nums.get(key2);
                    for (int value1 : values1) {
                        for (int value2 : values2) {
                            if ((key1 < key2 && value1 >= value2) || (key1 > key2 && value2 >= value1)) {
                                intersects = true;
                                break;
                            }
                        }
                        if (intersects) {
                            break;
                        }
                    }
                    if (intersects) {
                        break;
                    }
                }
            }
            if (!intersects) {
                count++;
            }
        }

        System.out.println(count);
    }
}
java
  • 2 2 个回答
  • 79 Views

2 个回答

  • Voted
  1. Best Answer
    tym32167
    2024-04-11T06:05:37Z2024-04-11T06:05:37Z

    你不必将所有事情都进行比较。

    看看你的照片

    例子

    假设您沿着坐标 (0,ai) 从左向右移动,您会发现如果 a0=1 且 b0=4,则 ai >= a0 且 bi<=b0 的任何其他线段都将与第一条线段相交。

    由于我们是从左到右,这意味着在处理下一对ai、bi时,为了了解这对是否与另一对相交,我们只需要知道之前所有值中的最大值aMax和bMax即可。如果 ai == aMax - 那么这些线段与前面的线段在点 ai 处相交。如果 bi <= bmax - 则线段 bi 与已处理的某个线段相交。

    这样,我们就得到了一个线性算法(除了 NlogN 排序之外)。C# 中的一个示例,我首先从左到右,然后从右到左。

    public int[][] NotIntersects(int[][] data)
    {
        Array.Sort(data, Comparer<int[]>.Create( (a,b) => a[0].CompareTo(b[0]) ));
        
        var edge = data[0][1];  
        var idexes = new HashSet<int>();
        
        for(int i=1; i<data.Length; i++)
        {
            if (data[i][1] <= edge || data[i][0] == data[i-1][0]) idexes.Add(i);
            edge = Math.Max(edge, data[i][1]);
        }
        
        edge = data[data.Length-1][1];
    
        for (int i = data.Length - 2; i >=0; i--)
        {
            if (data[i][1] >= edge || data[i][0] == data[i+1][0]) idexes.Add(i);
            edge = Math.Min(edge, data[i][1]);
        }
        
        return data.Where((x, i) => !idexes.Contains(i)).ToArray();
    }
    

    考试

    NotIntersects(new[] { 
        new[] { 1, 4 }, 
        new[] { 2, 5 }, 
        new[] { 3, 1 }, 
        new[] { 4, 5 }, 
        new[] { 5, 6 } })
        .Dump();
    

    结论

    在此输入图像描述

    • 6
  2. Stanislav Volodarskiy
    2024-04-11T07:00:20Z2024-04-11T07:00:20Z

    令a i为线段的下端,构造索引i k使得序列a i k不减少。

    类似地,索引j k使得序列b j k不减。

    对于一个线段 ( a m , b m ) 来说,它是孤独的,所有其他线段必须完全位于它的左侧或右侧。设它的左边有k 个线段,其余的都在右边。则i k = m - k个线段下端中单个线段下端的左侧。类似地,j k = m - k 个线段上端中单个线段上端的左侧。m的具体值并不重要。重要的是所有孤独段都有i k = j k。

    孤独线段的相邻线段的下端与它不重合:a i k-1 < a i k < a i k+1。同样,上端也不重合: b j k-1 < b j k < b j k+1。

    我们迭代k。在孤独片段之前开始的所有片段都必须在它之前结束。为此,我们根据段数创建一个标志数组。当段开始或结束时,相应的标志被反转。在孤独段之前,必须重置所有标志。

    下面的程序体现了这三个想法。运行时间为O(nlogn)。

    import java.util.*;
    
    public class Temp {
        private static class Index {
            private final boolean[] flags;
            private final int n;
            private final int[] a;
            private final int[] i; // a[i[k]] перечислены по возрастанию
    
            public Index(boolean[] flags, int[] a) {
                this.flags = flags;
                this.n = a.length;
                this.a = a;
                Integer[] index = new Integer[this.n];
                for (int i = 0; i < this.n; ++i) {
                    index[i] = i;
                }
                Arrays.sort(index, Comparator.comparingInt(i -> a[i]));
                this.i = new int[this.n];
                for (int k = 0; k < this.n; ++k) {
                    this.i[k] = index[k];
                }
            }
    
            // инвертирует флаг для отрезка на позиции k
            // возвращает один, если флаг установлен
            // возвращает минус один, если флаг снят
            public int flip(int k) {
                flags[i[k]] = !flags[i[k]];
                return (flags[i[k]]) ? 1 : -1;
            }
    
            // индекс отрезка на позиции k
            public int i(int k) {
                return i[k];
            }
    
            // конец отрезка на позиции k не пересекается с другими отрезками 
            public boolean distinct(int k) {
                return 
                    (k == 0     || a[i[k - 1]] < a[i[k]]              ) &&
                    (k == n - 1 ||               a[i[k]] < a[i[k + 1]])
                ;
            }
        }
    
        public static void main(String[] args) {
            Scanner s = new Scanner(System.in);
            int n = s.nextInt();
            int[] a = new int[n];
            int[] b = new int[n];
            for (int i = 0; i < n; ++i) {
                a[i] = s.nextInt();
                b[i] = s.nextInt();
            }
            boolean[] flags = new boolean[n];
            Index ia = new Index(flags, a);
            Index ib = new Index(flags, b);
    
            int answer = 0; // число одиноких отрезков
            int nFlags = 0; // число отрезков, которые начались и не закончились
            for (int k = 0; k < n; ++k) {
                if (
                    nFlags == 0        && // все отрезки завершились
                    ia.i(k) == ib.i(k) && // это концы одного отрезка
                    ia.distinct(k)     && // конец a не пересекается с другими
                    ib.distinct(k)        // конец b не пересекается с другими
                ) {
                    ++answer;
                }
                // перевернуть флаги и поправить счётчик установленных флагов
                nFlags += ia.flip(k) + ib.flip(k);
            }
            System.out.println(answer);
        }
    }
    
    • 1

相关问题

  • wpcap 找不到指定的模块

  • 如何以编程方式从桌面应用程序打开 HTML 页面?

  • Android Studio 中的 R.java 文件在哪里?

  • HashMap 初始化

  • 如何使用 lambda 表达式通过增加与原点的距离来对点进行排序?

  • 最大化窗口时如何调整元素大小?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5