字符串与数组的基本概念及LetCode真题

目录

数组

数组是什么

数组的基本操作

数组的新增操作

数组的删除操作

数组的查找操作

数组增删查操作的特点

链表存在的价值又是什么呢?

总结

字符串

字符串是什么

字符串的基本操作

字符串的新增操作

字符串的删除操作

子串查找(字符串匹配)

字符串匹配算法的案例

总结


数组

数组是什么

数组可以把这些具有相同类型的元素,以一种不规则的顺序进行排列,这些排列好的同类数据元素的集合就被称为数组。数组在内存中是连续存放的,数组内的数据,可以通过索引值直接取出得到。

实际上数组的索引就是对应数组空间,所以我们在进行新增、删除、查询操作的时候,完全可以根据代表数组空间位置的索引值进行。也就是说,只要记录该数组头部的第一个数据位置,然后累加空间位置即可。

数组的基本操作

数组在存储数据时是按顺序存储的,并且存储数据的内存也是连续的,这就造成了它具有增删困难、查找容易的特点。

数组的新增操作

数组新增数据有两个情况:

第一种情况,在数组的最后增加一个新的元素。此时新增一条数据后,对原数据产生没有任何影响。可以直接通过新增操作,赋值或者插入一条新的数据即可。时间复杂度是 O(1)。

第二种情况,如果是在数组中间的某个位置新增数据,那么情况就完全不一样了。这是因为,新增了数据之后,会对插入元素位置之后的元素产生影响,具体为这些数据的位置需要依次向后挪动 1 个位置。

数组的删除操作

数组删除数据也有两种情况:

第一种情况,在这个数组的最后,删除一个数据元素。由于此时删除一条数据后,对原数据没有产生任何影响。我们可以直接删除该数据即可,时间复杂度是 O(1)。

第二种情况,在这个数组的中间某个位置,删除一条数据。同样的,这两种情况的区别在于,删除数据之后,其他数据的位置是否发生改变。

数组的查找操作

数组查找也可以分为两种:

第一种基于位置的查找操作可以根据索引值,直接在 O(1) 时间复杂度内查找到某个位置的元素。

第二种基于数值的查找方法:是需要整体遍历一遍数组的。和链表一样,都需要 O(n) 的时间复杂度。

数组增删查操作的特点

归纳一下数组增删查的时间复杂度:

  • 增加:若插入数据在最后,则时间复杂度为 O(1);如果中间某处插入数据,则时间复杂度为 O(n)。
  • 删除:对应位置的删除,扫描全数组,时间复杂度为 O(n)。
  • 查找:如果只需根据索引值进行一次查找,时间复杂度是 O(1)。但是要在数组中查找一个数值满足指定条件的数据,则时间复杂度是 O(n)。

链表存在的价值又是什么呢?

首先,链表的长度是可变的,数组的长度是固定的,在申请数组的长度时就已经在内存中开辟了若干个空间。如果没有引用 ArrayList 时,数组申请的空间永远是我们在估计了数据的大小后才执行,所以在后期维护中也相当麻烦。

其次,链表不会根据有序位置存储,进行插入数据元素时,可以用指针来充分利用内存空间。数组是有序存储的,如果想充分利用内存的空间就只能选择顺序存储,而且需要在不取数据、不删除数据的情况下才能实现。

总结

在实际操作中,我们还要注意根据数组的优缺点合理区分数组和链表的使用。数组定义简单,访问方便,但在数组中所有元素类型必须相同,数组的最大长度必须在定义时给出,数组使用的内存空间必须连续等。

相对而言,数组更适合在数据数量确定,即较少甚至不需要使用新增数据、删除数据操作的场景下使用,这样就有效地规避了数组天然的劣势。在数据对位置敏感的场景下,比如需要高频根据索引位置查找数据时,数组就是个很好的选择了。

 

字符串

字符串是什么

字符串(string) 是由 n 个字符组成的一个有序整体( n >= 0 )。例如,s = "BEIJING" ,s 代表这个串的串名,BEIJING 是串的值。这里的双引号不是串的值,作用只是为了将串和其他结构区分开。字符串的逻辑结构和线性表很相似,不同之处在于字符串针对的是字符集,也就是字符串中的元素都是字符,线性表则没有这些限制。

在实际操作中,我们经常会用到一些特殊的字符串:

  • 空串,指含有零个字符的串。例如,s = "",书面中也可以直接用 Ø 表示。
  • 空格串,只包含空格的串。它和空串是不一样的,空格串中是有内容的,只不过包含的是空格,且空格串中可以包含多个空格。例如,s = "   ",就是包含了 3 个空格的字符串。
  • 子串,串中任意连续字符组成的字符串叫作该串的子串。
  • 原串通常也称为主串。例如:a = "BEI",b = "BEIJING",c = "BJINGEI" 。

 

字符串的存储结构与线性表相同,也有顺序存储和链式存储两种:

  • 字符串的顺序存储结构,是用一组地址连续的存储单元来存储串中的字符序列,一般是用定长数组来实现。有些语言会在串值后面加一个不计入串长度的结束标记符,比如 \0 来表示串值的终结。

  • 字符串的链式存储结构,与线性表是相似的,但由于串结构的特殊性(结构中的每个元素数据都是一个字符),如果也简单地将每个链结点存储为一个字符,就会造成很大的空间浪费。因此,一个结点可以考虑存放多个字符,如果最后一个结点未被占满时,可以使用 "#" 或其他非串值字符补全,如下图所示:

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

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

字符串的基本操作

线性表更关注的是单个元素的操作,比如增删查一个元素,而字符串中更多关注的是查找子串的位置、替换等操作。接下来以顺序存储为例,详细介绍一下字符串对于另一个字符串的增删查操作。

字符串的新增操作

字符串的新增操作和数组非常相似,都牵涉对插入字符串之后字符的挪移操作,所以时间复杂度是 O(n)。

字符串的删除操作

字符串的删除操作和数组同样非常相似,也可能会牵涉删除字符串后字符的挪移操作,所以时间复杂度是 O(n)。

子串查找(字符串匹配)

字符串的查找操作,是反映工程师对字符串理解深度的高频考点,这里需要你格外注意。

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

之后使用动态规划解


字符串匹配算法的案例

一道面试中常见的高频题目,这也是对字符串匹配算法进行拓展,从而衍生出的问题,即查找出两个字符串的最大公共字串。

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


总结

字符串的逻辑结构和线性表极为相似,区别仅在于串的数据对象约束为字符集。但是,字符串的基本操作和线性表有很大差别:

  • 在线性表的基本操作中,大多以“单个元素”作为操作对象;
  • 在字符串的基本操作中,通常以“串的整体”作为操作对象;

字符串的增删操作和数组很像,复杂度也与之一样。但字符串的查找操作就复杂多了,它是参加面试、笔试常常被考察的内容。

LetCode真题与范例

范例:翻转一个字符串

分析:字符串转换为数组,用两个指针分别从头尾开始交换。

数组

LetCode:242. 有效的字母异位词

public class Solution {

	public static void main(String[] args) {
		String s = "anagra";
		String t = "nagaram";
		System.out.println(isAnagram(s, t));
	}

	public static boolean isAnagram(String s, String t) {
		if (s.length() != t.length()) {
			return false;
		}
		int[] count = new int[26];
		char [] sArray = s.toCharArray();
		char [] tArray = t.toCharArray();
		for (int i = 0; i < s.length(); i++) {
			count[sArray[i] - 'a']++;
			count[tArray[i] - 'a']--;
		}

		for (int temp : count) {
			if (temp != 0) {
				return false;
			}
		}

		return true;
	}

}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值