两层for循环优化成一层for循环,时间复杂度直接降一个量级!

大家好,我是三叔,很高兴这期又和大家见面了,一个奋斗在互联网的打工人。

劳动最光荣,笔者祝大家五一假期快乐!

不废话,上代码:

当存在两个嵌套的 for 循环时,时间复杂度将取决于循环嵌套的层数和循环内部执行的操作。如果内部操作的时间复杂度是 O(1),则两个 for 循环的时间复杂度为 O(n^2),其中 n 是集合中元素的数量。以下是两个list的嵌套循环,它计算了两个集合的笛卡尔积:

 public static void main(String[] args) {
 		// 主题类list
        List<TopicVO> topicList = Arrays.asList(
                new TopicVO(1, 10, "主题1"),
                new TopicVO(2, 20, "主题2"),
                new TopicVO(3, 30, "主题3")
        );
		// 事件类list
        List<EventVO> eventList = Arrays.asList(
                new EventVO(1, 10, "事件1"),
                new EventVO(2, 20, "事件2"),
                new EventVO(3, 30, "事件3")
        );
        // 比较赋值操作
        topicList.stream().forEach(topicVO -> {
            eventList.stream().forEach(eventVO -> {
                if (topicVO.getId() == eventVO.getId() && topicVO.getName().equals(eventVO.getName())) {
                    // 如果满足上面的条件,就把topicVo的age字段赋值给eventVo的age字段
                    eventVO.setAge(topicVO.getAge());
                }
            });
        });
    }

笔者在开过过程中,由于业务逻辑的需要,需要对两个list进行遍历,取出符合判断条件的值,赋值到另一个对象,所以两个for循环就能解决问题。但是在随着测试数据的日积月累,数据量越来越大,这个接口的responseTime时间开始增加了,于是笔者在排查的过程中,就发现了这两个for循环“嫌疑”很大。

在 Java 集合中,单个 for 循环的时间复杂度通常是 O(n),而两个嵌套的 for 循环的时间复杂度可能是 O(n^2) 或更高,具体取决于循环嵌套的层数和内部操作的时间复杂度。

list转map,时间复杂度降低到O(n)

笔者处理逻辑需要和最外层的集合进行比较,所以这里把最外层的list使用Java8进行list转map(笔者这篇文章介绍了如何使用:Java8list转map
上代码:

 public static void main(String[] args) {
        List<TopicVO> topicList = Arrays.asList(
                new TopicVO(1, 10, "主题1"),
                new TopicVO(2, 20, "主题2"),
                new TopicVO(3, 30, "主题3")
        );

        List<EventVO> eventList = Arrays.asList(
                new EventVO(1, 10, "事件1"),
                new EventVO(2, 20, "事件2"),
                new EventVO(3, 30, "事件3")
        );
        // 之前的判断逻辑是同时满足两个条件才进行赋值操作,因为笔者的id和name字段能保证全局绝对的唯一,所以这里笔者将拼接属性作为唯一key

        // key: id + name
        // value: age
        Map<String, Integer> topicMap
                = topicList.stream().collect(Collectors.toMap(vo -> vo.getId() + vo.getName(), TopicVO::getAge));
                
		// 重点在这里
        for (EventVO eventVO : eventList) {
        	// 拼接新的key,如果key在map中,获取到map对象取到值(因为map的value就是我们需要的值,所以直接get(key)就可以拿到value值)
            String newKey = eventVO.getId() + eventVO.getName();
            if (topicMap.containsKey(newKey)) {
                eventVO.setAge(topicMap.get(newKey));
            }
        }
    }

这样,两层for循环,笔者通过list转map,成功让这两层for循环的时间复杂度降低了一个量级,避免了笛卡尔积,并且代码也变得整洁起来。

思考:map效率一定比list高吗

对于 List 和 Map 的遍历,它们的效率取决于具体的使用场景。一般情况下,如果你只是需要简单地遍历所有元素,那么 List 的遍历会更加高效。这是因为 List 的内部数据结构是一个数组,所以它的遍历速度会比 Map 的遍历速度快一些。

但是,如果你需要在遍历的过程中进行查找、删除、更新等操作,那么 Map 的遍历会更加高效。这是因为 Map 内部使用了哈希表的数据结构,它可以通过 key 快速定位到对应的 value,而 List 的查找、删除、更新等操作都需要遍历整个列表,效率相对较低。

总之,对于 List 和 Map 的遍历,要根据具体的使用场景来选择。如果只是简单的遍历,选择 List 会更加高效;如果需要进行复杂的操作,选择 Map 会更加高效。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我是三叔

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

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

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

打赏作者

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

抵扣说明:

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

余额充值