数据结构与算法笔记(七)字符串

字符串string是由n个字符组成的有序整体

字符串分为顺序储存结构和链式储存结构两种

  • 顺序储存结构:是用一组地址连续的存储单元来存储串中的字符序列,一般是用定长数组来实现。有些语言会在串值后面加一个不计入串长度的结束标记符,比如 \0 来表示串值的终结。
  • 链式储存结构:与线性表是相似的,但由于串结构的特殊性(结构中的每个元素数据都是一个字符),如果也简单地将每个链结点存储为一个字符,就会造成很大的空间浪费。因此,一个结点可以考虑存放多个字符,如果最后一个结点未被占满时,可以使用 "#" 或其他非串值字符补全

在链式储存中,每个节点设置字符数量的多少与串的长度、可以占用的储存空间以及程序实现的功能有关

  • 如果字符串中包含的数据量很大,但是可用的存储空间有限,那么就需要提高空间利用率,相应地减少结点数量。
  • 如果程序中需要大量地插入或者删除数据,如果每个节点包含的字符过多,操作字符就会变得很麻烦,为实现功能增加了障碍。

因此,串的链式存储结构连接串与串操作时有一定的方便,但不如顺序存储灵活,在性能方面也不如顺序存储结构好。

字符串的基本操作

字符串和线性表的操作类似,但字符串针对的是字符集,所有元素都是字符。

线性表关注的是单个元素的操作,增删查一个元素;字符串关注的是查找字串的位置、替换等操作。

以顺序储存为例

新增操作:

类似于数组的新增,涉及到插入字符串之后的挪移,时间复杂度为O(n)。

直接增加到字符串的最后也可以叫做字符串的连接,时间复杂度为O(1)。

删除操作:

类似于数组的删除,涉及到插入字符串之后的挪移,时间复杂度为O(n)。

直接删除字符串的最后的若干字符串也可以叫做字符串的连接,时间复杂度为O(1)。

查找操作:(重点)

高频考点

一个字符串a = "asdasfgsdgadgf",判断字符串b = "asdf"在a中是否存在。如果字符串b中的每个字符都在a中出现过,这不能证明字符串b在a中出现,只是单个字符都出现了,他们是否连在一起不知。

判断子串是否出现

子串查找操作(字符串匹配)

主串和模式串:

在字符串 A 中查找字符串 B, A 是主串,B 是模式串。主串的长度记为 n,模式串长度记为 m。由于是在主串中查找模式串,主串的长度肯定比模式串长,n>m。因此,字符串匹配算法的时间复杂度就是 n 和 m 的函数。

  • 按照逻辑是从主串的第一位开始,判断a的第一个字符和b的第一个字符是否相等,
  • 如果相等,继续判断主串的第i个字符和模式串的第i个字符是否相等,全部相等则匹配成功。
  • 如果不相等,重新判断主串的下一个字符和模式串的第1个字符是否相等,重复判断,到结尾都没有全部匹配的就没有

从实现的角度看,需要两层循环。这种匹配算法的时间复杂度为O(nm)。

public void s1() {
    String s = "asdfadsfafasfa";
    String t = "asda";
    int isfind = 0;

    for (int i = 0; i < s.length() - t.length() + 1; i++) {
        if (s.charAt(i) == t.charAt(0)) {
            int jc = 0;
            for (int j = 0; j < t.length(); j++) {
                if (s.charAt(i + j) != t.charAt(j)) {
                    break;
                }
                jc = j;
            }
            if (jc == t.length() - 1) {
                isfind = 1;
            }
        }
    }
    System.out.println(isfind);
}

例:查找出两个字符串的最大公共字串

假设有且仅有 1 个最大公共子串。比如,输入 a = "13452439", b = "123456"。由于字符串 "345" 同时在 a 和 b 中出现,且是同时出现在 a 和 b 中的最长子串。因此输出 "345"。

代码结构:

  • 第一步需要两层的循环去查找共同出现的字符,时间复杂度为 O(nm)。
  • 一旦找到了共同出现的字符之后,还需要再继续查找共同出现的字符串,

总共是3层循环,时间复杂度是 O(nmm),即 O(nm²)。

public void s2() {
    String a = "123456";
    String b = "13452439";
    String maxSubStr = "";
    int max_len = 0;
		
    for (int i = 0; i < a.length(); i++) {
        for (int j = 0; j < b.length(); j++){
            if (a.charAt(i) == b.charAt(j)){
                for (int m=i, n=j; m<a.length()&&n<b.length(); m++,n++) {
                    if (a.charAt(m) != b.charAt(n)){
                    break;
                    }
                    if (max_len < m-i+1){
                        max_len = m-i+1;
                        maxSubStr = a.substring(i, m+1);
                    }
                }
            }
        }	
    }
    System.out.println(maxSubStr);
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值