需要注意的是 :在CSDN某些博文中,有很多博主把判断子集的代码写成了判断连续子序列的代码,我认为这是不对的。因为连续子序列和子集有着明显的区别,连续子序列一定是子集,但子集不一定是连续子序列。
子序列和子集之间也有着区别。
因此大家写代码时要注意一点,
这是比较好的 思路算法
见:https://blog.csdn.net/qq_39189509/article/details/78158277
但在考场上使用这种暴力的算法更加简单易行:
Bool subset(LinkList la, LinkList lb) {
LinkNode * pa,*pb;
pa=la->next;
while(pa)
{ pb=lb->next;
while(pb&&(pb->data!=pa->data)) pb=pb->next;
if(!pb) return False;
pa=pa->next; } return True;
}
算法时间复杂度O(A.Length*B.Length)
同样,顺序表思路一致:
Bool subset(Sqlist LA,Sqlist LB){
int i=0;
while(i<LA.length){
int j=0;
while(j<LB.length)
if(LB.data[j]!=LA.data[i]) j++;
if(j=LB.length) return Flase;
i++;
}
reture True;
}
需要注意的是,空集是任何集合的子集,因此可以添加一个条件判断A序列是否是空集。
对于评论区提出的集合A = {1, 2, 2},B = {1, 2, 3}。直接运行上述算法会返回True,但实际上A不是B的子集。
问题出在对重复元素的处理上。这两种算法都没有考虑到集合中可能存在重复元素的情况。
为了解决这个问题,需要在内层循环中增加一点逻辑:
对于链表:
Bool subset(LinkList la, LinkList lb) {
LinkNode *pa, *pb;
pa = la->next;
while(pa) {
pb = lb->next;
while(pb && pb->data != pa->data) {
if(pb->data == pa->data) break; // 增加判断逻辑
pb = pb->next;
}
if(!pb) return False;
pa = pa->next;
}
return True;
}
对于顺序表:
Bool subset(Sqlist la, Sqlist lb) {
int i = 0;
while(i < la.length) {
int j = 0;
while(j < lb.length) {
if(lb.data[j] == la.data[i]) break; // 增加判断逻辑
j++;
}
if(j == lb.length) return False;
i++;
}
return True;
}
增加了判断重复元素的逻辑后,就可以正确处理包含重复元素的集合情况了。