3sum 及TreeMap的线性遍历

此题我的思路是,先形成一个 num与其频率的 treeMap, 然后每次选定一个左边的num,这样其他两数必在此key的右边,而且其和也被决定了,可用左右两指针互相逼近的方法获得。遍历左边num的时间为O(n), 找右边两数也是O(n),所以时间复杂为O(n2)。应该说这已经是优化过的算法了,然后在实现中https://leetcode.com/submissions/detail/245681661/,却因为我对TreeMap的不熟悉,导致速度并不理想。问题在哪里呢?我一看源代码,以TreeMap的ceilingKey方法为例,我用它来推动最小数和左指针的右移,脑子里想的是有序数组,每移一次仅O(1),但是实际上呢,人家并没有用到中序遍历的后序指针,每次都是从root往下进行二叉搜索,这时间就不是O(1)而是O(log n)了。如此总体时间变成n2 (log n)2.

https://leetcode.com/submissions/detail/245697101/中我做了改进,不再直接用treeMap来遍历,而是用new ArrayList(entrySet)将它的所有键值对包成一个有序数组,再对这个数组进行遍历。如此时间应该真的是O(n2)了

此前的相关文章:如何对map的entry进行排序

此时我心里还是有疑问,难道TreeMap的遍历也会不是O(n)的吗。于是我在本地做了个实验:

		TreeMap<Integer,Integer> map = new TreeMap<Integer,Integer>();
		int t = 20000000;
		while(--t>=0) {
			map.put(t, 1);
		}
		
		long t0 = System.currentTimeMillis();
		int sum = 0;
		List<Integer> sortedKeys = new ArrayList<Integer>(map.keySet());
		long t11 = System.currentTimeMillis();
		System.out.println(t11-t0);
		for (int i = 0; i < sortedKeys.size() ; ++i) {
			sum += sortedKeys.get(i);
		}
		long t1 = System.currentTimeMillis();
		System.out.println(t1-t11);
		
		int sum2 = 0;
		Set<Integer> keySet = map.keySet();
		for(int num : keySet){
			sum2 += num;
		}
		long t2 = System.currentTimeMillis();
		System.out.println(t2-t1);

		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()) {
			sum2 += it.next();
		}
		long t3 = System.currentTimeMillis();
		System.out.println(t3-t2);
   事实证明直接对keyset进行遍历是线性的,因为如果它是O(n logn), 那么随着数据规模的变大,它对线性O(n)的倍数会增大。而事实上我反复实验,它们基本上成正比。

于是我准备做如下权衡,对treemap进行遍历时,如果不会改动treemap,又是简单的从左到右,则直接遍历。如果会改动treemap,或者要进行更灵活的遍历,比如此题,则用数组包装下对数组遍历吧。。

另外,当对TreeMap既要进行key的遍历,也要进行v的遍历时,应该用entrySet()而不是keySet()。因为TreeMap.get方法的时间复杂度是O(logn),而非O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

qq_23204557

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

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

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

打赏作者

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

抵扣说明:

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

余额充值