1 用两个变量表示下标,一个表示奇数下标,一个表示偶数下标
奇数下标的动作是:如果在自己位置上的数不是0,就停止,如果是0,就自加2,一直到指得数不为0为止。
偶数下标的动作是:如果在自己位置上的数不是1,就停止,如果是1,就自加2,一直到指得数不为1为止。
等到两方都停止的时候,交换双方值。循环下去,应该一次遍历就可以搞定。
2 设一个临时分量temp,下标分量index,然后用i遍历数组,遇到0,就和index的值交换,此时index+1有两种情况,如果不等于i,index+1所指的值此时肯定为1(因为index比i小,不会存在是0的情况),所以直接index自增2。如果等于i,i指向的值取非,
这种的话会有意外,比如index ==
i,比如一开始就是0001.....这种数组,那么就需要把"用i遍历数组,遇到0,就xxxxxx"这个思路换成"用i遍历数组,遇到1,就xxxxxx"。
两个都是遍历一次就行了,不过第二个思路要比第一个思路复杂很多,纸上画了很久才大概摸清楚。不过我不知道O(1)空间复杂度是什么意思?
2008/6/4 pongba <pon...@gmail.com>:
--
Yours Sincerely
Kun
blog: www.forwind.cn
第三题有点意思,我有两个思路:
1 用两个变量表示下标,一个表示奇数下标,一个表示偶数下标
奇数下标的动作是:如果在自己位置上的数不是0,就停止,如果是0,就自加2,一直到指得数不为0为止。
偶数下标的动作是:如果在自己位置上的数不是1,就停止,如果是1,就自加2,一直到指得数不为1为止。
等到两方都停止的时候,交换双方值。循环下去,应该一次遍历就可以搞定。
然后因为先想的第二个思路,然后花了很久的时间,觉得不应该这么麻烦的,特别是如何解决"交换"的问题,开专门开辟一个temp变量,简直伤透了脑筋
想到后来干脆就换个思路,搞两个下标来解决交换的问题,然后发现换来换去,就是把0放到偶数位上去,1放到奇数位上去,那干脆就一个下标指奇数位,一个下标指偶数位,大家一起遍历找位置不对的地方,等大家都找到(也就是停止)的时候,一交换,最后肯定位置就对了。
举了几个特例一验证,差不多,就写上来了。
2008/6/4 pongba <pon...@gmail.com>:
--
首先就确定必须交换,因为只能遍历一次
然后因为先想的第二个思路,然后花了很久的时间,觉得不应该这么麻烦的,特别是如何解决"交换"的问题,开专门开辟一个temp变量,简直伤透了脑筋
想到后来干脆就换个思路,搞两个下标来解决交换的问题,然后发现换来换去,就是把0放到偶数位上去,1放到奇数位上去,那干脆就一个下标指奇数位,一个下标指偶数位,大家一起遍历找位置不对的地方,等大家都找到(也就是停止)的时候,一交换,最后肯定位置就对了。
举了几个特例一验证,差不多,就写上来了。
这个过程应该也是O(n)的。
2008/6/4 pongba <pon...@gmail.com>:
--
新的理论从少数人的主张到一统天下,并不是因为这个理论说服了别人抛弃旧观点,而是因为一代人的逝去。
My blog: http://googollee.blog.163.com
这个corner,可以在验证完一遍后增加一次对奇数位的扫描来解决吧:
奇数指针不动,另一个指针从后向前扫奇数位,碰到为0的奇数位就与奇数指针交换,且奇数指针按之前的方法递增。直到两个指针相遇。
这个过程应该也是O(n)的。
2008/6/4 alai <ala...@gmail.com>:
所以……这样能算一次遍历么?
2008/6/4 alai <ala...@gmail.com>:
用一个i指向当前下标,用一个e指向第一个出错的位置,当前位置正确时,e随着i一起前进,当前位置不正确时,e停住,i继续前进寻找e位置上需要的那个数字,当i到底时,算法结束。
用pongba的例子110101,x代表空格:
======== 1 ========
i
110101
e
======== 2 ========
xi
110101
e
======== 3-1 ========
xxi
110101
e
======== 3-2 找到了,i和e交换,e前进至i ========
xxi
011101
xxe
======== 4 ========
xxxi
011101
xxe
======== 5-1 ========
xxxxi
011101
xxe
======== 5-2 找到了,i和e交换,e前进至i ========
xxxxi
010111
xxxxe
======== 6 =========
xxxxxi
010111
xxxxe
========= end ==========
另外问一句,如果我凭空构造一个数组出来直接替换原数组,算不算破坏O(1)?
--
Any complex technology which doesn't come with documentation must be the best
available.
其实我觉得,"只能遍历一次"这个条件有点模糊,是否要理解为"只能有一个单向迭代器且只能遍历一次",还是可以理解为"可以有一个以上的单向迭代器,每个只能遍历一次",抑或是"可以是双向迭代器,遍历的过程中可以回溯"?有许多不确定的地方。LS几位给出的解法都用了两个迭代器,各遍历一次,这是否符合题意呢?
我刚才也想了一下,如果不允许偶数指针回扫,貌似这个问题还很难解决,这个问题实际上是:如何排序本身所在位置的奇偶性正确,只是位置靠后(位置编号不对)的元素。
2008/6/4 翁翊成 <wen...@gmail.com>:
--
所以我有另外一个思路,但是不知道是不是破坏了空间O(1)。。。
反正最后结果的形式已经知道了,惟一的区别是0101xx最后的x是0还是1,那么只要扫一遍数组,得到0和1之间的差,比如0比1多差就是负数,一样多就是0,1比0多就是正数,然后构造一个数组直接换掉原来的就行了
2008/6/4 xxmplus <xxm...@gmail.com>:所以我有另外一个思路,但是不知道是不是破坏了空间O(1)。。。
反正最后结果的形式已经知道了,惟一的区别是0101xx最后的x是0还是1,那么只要扫一遍数组,得到0和1之间的差,比如0比1多差就是负数,一样多就是0,1比0多就是正数,然后构造一个数组直接换掉原来的就行了
只是以为重新写一次数组算一次遍历......所以我才用了条件判断,分情况讨论,导致这个思路如此复杂.....
2008/6/4 pongba <pon...@gmail.com>:
--
windstorm说上次一次给的题目太多,抱歉,没有筛选。这次给出两道不错的题目。
第一道是上次转载的阅微堂那里(后者从这里转载的,上面有很多不错的题目,分类也井井有条),silwile说这道题不错,我就做了一下,的确不错,小巧又不失精彩。据说也是微软的经典面试题之一。
1. There is a circular track. There are n gas stations of capacity ci. To go from one station to the next station it takes certain amount of gas gi. For any station the gas available may not be enough to get to the next station. Write a linear time algorithm to find the correct station in which we must start in order to complete one round around the track.
第二道题目是Amazon的面试题,从题目的形式上感觉是道挺不错的题目。
2. Given two arrays A [1..n] and B[1..m], find the smallest window in A that contains all elements of B. That is, find a pair <l,k> such that A[l..k] contains B[1..m] For example, given A = 3,1,5,7,3,5,2 and B = 5,3 then the smallest window is [3,5].
最后顺带一道趣题吧。
3. 有一个01数组,现在要你对它进行重排(即保持0和1的数目不变),使得成为这样的形式:0101..01xxx.. 即01间隔,然后多出来的0或者1放到后面(用xx表示)。例如110110重排为010111。要求O(1)空间复杂度,以及只能遍历一次。
--
刘未鹏(pongba)|C++的罗浮宫
http://blog.csdn.net/pongba
TopLanguage
http://groups.google.com/group/pongba
第2题:
暴力的方法也能做到n^2,上面给了一个n^3的,惭愧啊。
首先枚举A中一个元素A[i],使得A[i]==B[0],然后以i为起始点,通过贪心的方法,找出能包含B所有元素的最短窗口。
这个方式n^2的。
第2题的pongba说的那个复杂度分析。
代码如下:
int [] A=...;
int [] B=...;
int res=10000000;
for(int i=0;i<A.length;i++) {
if(A[i]==B[0]) {
int x=i,y=0;
while(y<B.length) {
while(x<A.length && A[x]!=B[y])x++;
if(x==A.length)break;
x++;
y++;
}
if(y==B.length) {
res=Math.min(res, x-i);
}
}
}
偷懒了,代码中只求区间的最小长度。
外层循环是n次,内层两个循环的总次数<2n, 因为每次循环x或者y都在增加。
因此总的复杂度是n^2的
第一题很简单的, 用推箱子方法. 把油反向往前推.
先假设顺时针可以有解的话, 从任意一点开始, 逆时针往前走, 遇路减路, 遇油加油. 在油站如果结果为正, 把当前的和记下, 把和刷成0, 然
后从下条路开始, 继续同样的方法往前推, 推的结果是所有局部和为负的都往前推, 直到在某个点和某个正的值合并. 这样, 如果有可行解, 最后环
上就没有负的元素, 有些油站是0或者正的, 从任意一个正的开始, 顺时针走, 肯定有解.
O(N) [最多往前推积木推2N个点]
我来公布第一题的最佳答案吧,是我在7年前从一北大朋友那听来的,他的解答是他的数学老师给的:
假设汽车带有0油从任意一点出发,遇油加,遇路减,即便油量为负数也无所谓,循环一圈后,找到值最小的那个点,从那个点出发就肯定可以跑完(只需要进行n次计算)
呵呵,可惜我是刚刚听到这个问题时就顺便听到的答案,而这个答案偏偏又很容易被证明且又很精巧
然后,偶就不知道那个数学教授的思路是怎么来的了:(
呵呵,当时从朋友口中得知的是,他的教授对于此题不屑一顾,完全是即时给出该解
估计对于他来说,这种思维方式已经成了一种本能了吧
嗯 不错 考察逆否命题
但是实际思考的时候,有时会在某一点有很多可能,必须抽象出确切的概念才能恰好达到目标。比如这里我觉得核心是意识到sigma再也不能小了这个概念,而通常的思路是由于sigma是负数了,所以就此打住,然后考虑从下一个点开始。因此错过了一次走完,统计全部信息的机会。
正巧pangba提到了这两个关于单链表的题 请大家基于这两道题,基于启发式思维的方法 想这一题:
一个有环的单链表,如何线性地打开他的环(即找到指回环的那个元素 让他的Next 指针变成NULL)
基于上两题,这个题目就不难了。
比如一个可能有环的单链表,如何线性地探测出它是否有环:
一个甚为精巧的思路是用两个迭代器,后者是前者速度的两倍,如果n步内后者能追上前者,则有环。
第一个思路有点bug,但是后面朋友patch了。
----------------------------------------------------------------------------------
Yours Sincerely
Kun
blog: www.forwind.cn
2008/7/13 nextRainbow <wangwe...@gmail.com>:
----------------------------------------------------------------------------------
Yours Sincerely
Kun
blog: www.forwind.cn
2008/7/13 dnpg <dnpg...@gmail.com>: