周五晚上去听了下宣讲,然后做了套题。
做完觉得还不错,晚上睡觉的时候,各种题目突然又闯进脑袋,然后就意识到一些错误。很多时候,自我沉淀一下总会发现一些问题,同时又能把问题化解了。
下面说两个问题。
一个是分汤问题。说,两个人分一碗汤,没有第三方介入,要他们自己分,并且不产生争论。所以,这两个人有了这样一个策略,一个人分,另一个人先选。接下来让你设计一个策略,三个人分汤。
我当时写下的答案是:A分,B调整,C先选,再A选,再B选。但,后来觉得A分这个步骤都可以被忽略了。要是BC联合作弊的话,A就会拿到最少的了。
后来想想,这样应该是没问题了的:A 分汤,B,C分别选一份,剩下的一份就是A的,然后,B和C做两个人分汤时的步骤,一个人做调整,另一个人先选。
这样的话,避免了联合作弊,并且每个人都会为了自己的利益从最平均的角度出发。
另一个问题是,一个数组,有正有负,求其中某一段连续的子序列之和,使得这个和最大。
这个问题回来后一查,发现什么编程珠玑,编程之美上都有,分析了好几种方式和相应的复杂度。
好吧,我承认我好挫,以前没见过。
但这挡不住我的聪明才智啊~~哦哈哈!!虽然事后我意识到在卷子上我没写得足够充分和完全准确。于是现在写了下自己的思路。
http://www.cppblog.com/jake1036/archive/2011/03/12/141532.aspx 这个地址上也有类似的分析。可以参考下。
这篇博文的第二种解法就是我当时想到的,n^2这种级别的解法我觉得写到卷子上就显得太业余了,所以,除非完全想不到其他解法,不然不会拿出来献丑。问题是,这个作者把这个方法也实现成n^2的复杂度了,我表示很失望。其实完全可以是线性的。
这对给定的数组a[],额外定义个数组S ,有S[i] 表示数组a[0]到a[i]之间的元素之和,那么S[j]-S[i] 的差值,表示a[i]到a[j]之间和。然后,S[n]中找两个数字,使得下标大的数字减去下表小的数字所得的差值最大,即: 在S[n]中找S[i] 和S[j] ,使得 S[i] - S[j] 的值最大,并且 i > j 。这是可以在线性时间内完成的。
另外,做一个小小的修正,在S中的元素全部往后挪一个,S[0]置为0,这样就可以取到a中元素从头到某一位置的和为最大的情况。也就是S[i]-S[0]为最大值。
详细的实现代码如下:
可以看到,遍历的两遍数组,一遍是计算S,另一遍是在S中找最大差值。当然,这个代码改一下,完全可以做到遍历一遍,还能把辅助空间S给省下来,这样的话就得把a给改 了,所以,S的空间貌似不太好省了。最漂亮的实现还是subSum1。
然后做了相应的测试,手工设计了几组数据后还随机生成进行了测试,暂时没发现问题。测试用的基准是暴力解法,即算出a中任意[i,j]之间的各个和,然后取最大值。
后面没事的时候还是得看看一些经典的书,学习一些方法。不然老是靠自己的思考去解决别人已经给出有没方法的问题还是显得有那么些差距。。。