我们在涉及2个集合内的元素比较时,通常会涉及2重循环。比如在字符串中查找子串。返回子串位置,如果没有,返回-1.这里假设两个集合大小分别为m,n。即为source[m],target[n],m>=n。
最差情况,对于source中每一个元素m’,都需要和target中n个元素进行比较,时间复杂度为O(m*n)。这里必须要通过2重循环才能覆盖全部情况。小技巧是通过2个游标来指示source,一个用来遍历source,一个用来和target比较。这也符合设计模式里的解耦原则。
```cpp
int strStr(string &source, string &target) {
// Write your code here
unsigned int size_of_s = source.size();
unsigned int size_of_t = target.size();
if (size_of_t == 0)
return 0;
unsigned int cursor_to_t =0;
unsigned int cursor_to_s =0;
while (cursor_to_s<size_of_s){
unsigned int cursor_to_cursor_s = cursor_to_s;
while(cursor_to_t<size_of_t){
if (source[cursor_to_cursor_s] != target[cursor_to_t]) {
cursor_to_t = 0; //target位置归0。
break; //跳出当次循环。
}
else if(source[cursor_to_cursor_s] == target[cursor_to_t]){
cursor_to_cursor_s++;
cursor_to_t++;
}
if (cursor_to_t == size_of_t)
return cursor_to_s; //返回第一次匹配的头位置。
}
cursor_to_s++;
}
return -1;
}
同样是两个集合的合并排序数组问题。合并两个有序升序的整数数组A和B变成一个新的数组。新数组也要有序。A[m],B[n],和上面那个问题的输入条件几乎完全一样。我们是否也需要通过2重循环来解决呢。这里思路是建立一个队列,A中的每一个元素m’和B中的元素相比较,把min(A,B)放到队列里。由于A,B均为顺序表。所以A[0]和B[0]比较后,A[1:m]或者B[1:m]中的元素就不用表了。若A[0]<B[0].则A[0]<B[1:m]。所以,这种思路下时间复杂度为O(m+n)。这里的循环只要一个就可以了。这里循环条件为:while i < len(A) and j < len(B):。最坏条件就是循环m+n-1次。即为m+n次。and表示两个数组中任何一个遍历完成即退出循环。
def mergeSortedArray(self, A, B):
# write your code here
C=[]
i,j=0,0
while i < len(A) and j < len(B):
if A[i] < B[j]:
C.append(A[i])
i+=1
elif A[i] == B[j]:
C.append(A[i])
C.append(B[j])
i+=1
j+=1
else:
C.append(B[j])
j+=1
if i==len(A):
C.extend(B[j:])
if j==len(B):
C.extend(A[i:])
return C
结论:
1,不是涉及2个集合的比较操作就需要多重循环。
2,和我们采用算法的时间复杂度有关,时间复杂度就是算法的最大运算次数。设计的循环必须与其相匹配。