查找包含特定字符最短片段

1 篇文章 0 订阅
1 篇文章 0 订阅

       原地址(表示一下对原作者的敬意,哈哈):查找包含特定字符最短片段 -- 修江的芦苇


        csdn不允许回复里加那么多代码,只有把这个网址写回去咯~


这里,再重新说一下题的意思:

        原文如下:

                   找出一个字符串包含的特定的字符最短的片段,例如abcccda,包含bd,那么最短的是bcccd(实际原题是单词,每个词就像一个字符)

        解释一下:

               对特定字符没有顺序要求,比如包含acd,那么该题的结果是cda(最后3个)。


        小生只在此说一下自己的思路咯:

               维护一个双向链表,每次找到特定字符就把该节点置于链表的末尾,当链表的长度达到特定字符的个数时,就表示有结果了。如果链表结尾的位置减去链表头部的位置+1等于了特定字符的个数时,则产生最优解了。


        如何验证结果的正确性呢?

        假设,原字符串中有很多重复的,如 aaaaaabbbbbcccccccccdddddaaaabdccdcbc,包含bd,最短的怎么找呢?当找到一个b时,并没有结果,那么这时候,我选择哪个b呢?很明显,越靠后的,产生的结果才会更优(贪心一下咯~),那就选择最后一个b。当d出现时,bd都已经存在了:"bcccccccccd",那么就已经产生出一个结果了,这个结果是不是最优呢?看最后一个b和第一个d之间的距离,明显大于2,很好,继续往后找。再后面再找的过程中,很碰到一个d就会出现一个结果,但结果比之前的要差,抛弃不要。经过一串a我们又发现了一个b,哈,这个时候的子串"daaaab"长度比之前要小,那么它就是至今为止的最优解了。但很不幸的是紧跟其后的有一个d,那这个时候的子串"bd",刚好是特定字符的个数,还用往后找吗?不需要了,已经找到了。


        好了,臭屁到此为止。Talk is cheap, show me the code:


#include <stdio.h>
#include <string.h>

int main() {
	char* s = "abcccda";
	char* t = "bd";
	int t_len;

	char is_given[128];
	memset(is_given, 0, sizeof(is_given));
	for (t_len = 0; t[t_len]; t_len++) {
		is_given[t[t_len]] = 1;
	}

	char prev[128], next[128], head, end;
	int pos[128], cnt;
	memset(prev, -1, sizeof(prev));
	memset(next, -1, sizeof(next));
	memset(pos, -1, sizeof(pos));
	head = end = 0;
	cnt = 0;

	int left = 0, right = 1 << 30;

	int i;
	for (i = 0; s[i]; i++) {
		if (!is_given[s[i]]) {
			continue;
		}

		pos[s[i]] = i;
		if (s[i] == head) {
			if (head != end) {
				head = next[head];
				prev[next[s[i]]] = -1;
				next[s[i]] = -1;
				next[end] = s[i];
				end = s[i];
			}
		} else if (s[i] == end) {
			// pass
		} else {
			if (head) {
				if (prev[s[i]] == -1 && next[s[i]] == -1) {
					next[end] = s[i];
					prev[s[i]] = end;
					end = s[i];
					cnt++;
				} else {
					next[prev[s[i]]] = next[s[i]];
					prev[next[s[i]]] = prev[s[i]];
					next[end] = s[i];
					prev[s[i]] = end;
					end = s[i];
				}
			} else {
				head = end = s[i];
				cnt++;
			}
		}

		if (cnt == t_len && pos[end]-pos[head]<right-left) {
			left = pos[head];
			right = pos[end];
			if (right-left+1 == t_len) {
				break;
			}
		}
	}

	if (cnt != t_len) {
		printf("Not found!\n");
	} else {
		printf("s[%d:%d]\n", left, right+1);
		for (i = left; i <= right; i++) {
			printf("%c", s[i]);
		}
		printf("\n");
	}

	return 0;
}



         运行结果:

         s[1:6]
         bcccd


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值