3076. 数组中的最短非公共子字符串

题目描述:

给你一个数组 arr ,数组中有 n 个 非空 字符串。

请你求出一个长度为 n 的字符串 answer ,满足:

  • answer[i] 是 arr[i] 最短 的子字符串,且它不是 arr 中其他任何字符串的子字符串。如果有多个这样的子字符串存在,answer[i] 应该是它们中字典序最小的一个。如果不存在这样的子字符串,answer[i] 为空字符串。

请你返回数组 answer 。

示例 1:

输入:arr = ["cab","ad","bad","c"]
输出:["ab","","ba",""]
解释:求解过程如下:
- 对于字符串 "cab" ,最短没有在其他字符串中出现过的子字符串是 "ca" 或者 "ab" ,我们选择字典序更小的子字符串,也就是 "ab" 。
- 对于字符串 "ad" ,不存在没有在其他字符串中出现过的子字符串。
- 对于字符串 "bad" ,最短没有在其他字符串中出现过的子字符串是 "ba" 。
- 对于字符串 "c" ,不存在没有在其他字符串中出现过的子字符串。

示例 2:

输入:arr = ["abc","bcd","abcd"]
输出:["","","abcd"]
解释:求解过程如下:
- 对于字符串 "abc" ,不存在没有在其他字符串中出现过的子字符串。
- 对于字符串 "bcd" ,不存在没有在其他字符串中出现过的子字符串。
- 对于字符串 "abcd" ,最短没有在其他字符串中出现过的子字符串是 "abcd" 。

提示:

  • n == arr.length
  • 2 <= n <= 100
  • 1 <= arr[i].length <= 20
  • arr[i] 只包含小写英文字母。

解题分析及思路:

思路:

本题可以采用哈希表的方式来解决:

  • 首先我们需要遍历数组,将每个字符串的所有子字符串存入哈希表中,统计每个子字符串出现的次数,注意需要保证单个字符串的子字符串只存一次
  • 然后再次遍历数组,在哈希表中找出每个字符串所对应的最短非公共子字符串,注意需要优先遍历长度最长的子字符串,因为这样保证了字典序最小。

最短非公共子字符串满足要求:

  • 在哈希表中仅出现过一次,出现过一次即代表没有在其他字符串中出现过
  • 长度最短,因为我们是优先遍历长度最长的子字符串,所以长度最短的子字符串一定是最短非公共子字符串
func shortestSubstrings(arr []string) []string {
	var subM = make(map[string]int)
	for index := range arr {
		var m = make(map[string]bool)
		for left := 0; left < len(arr[index]); left++ {
			for right := len(arr[index]); right >= left+1; right-- {
				m[arr[index][left:right]] = true
			}
		}
		for key := range m {
			subM[key]++
		}
	}
	var results []string
	for index := range arr {
		var result string = arr[index]
		var flag bool
		var left, count = 0, len(arr[index])
		for count > 0 {
			right := left + count
			for right <= len(arr[index]) {
				subS := arr[index][left:right]
				if v, ok := subM[subS]; ok && v == 1 && (len(subS) < len(result) || subS <= result) {
					result = subS
					flag = true
				}
				left++
				right++
			}
			count--
			left = 0
		}
		if !flag {
			result = ""
		}
		results = append(results, result)
	}
	return results
}

复杂度:

  • 时间复杂度:O(M*N)
  • 空间复杂度:O(M*N)

执行结果:

  • 执行耗时:90 ms,击败了100.00% 的Go用户
  • 内存消耗:8.39 MB,击败了100.00% 的Go用户

通过次数 6.2K 提交次数 12.6K 通过率 49.7%

Related Posts

1026. 节点与其祖先之间的最大差值

## 题目描述:给定二叉树的根节点 root,找出存在于 不同 节点 A 和 B 之间的最大值 V,其中 V = |A.val - B.val|,且 A 是 B 的祖先。(如果 A 的任何子节点之一为 B,或者 A 的任何子节点是 B 的祖先,那么我们认为 A 是 B 的祖先)示例 1: ![](/img/leetcode/1026节点与其祖先之间的最大差值/tmp-tre

read more

1038. 从二叉搜索树到更大和树

## 题目描述:给定一个二叉搜索树 root (BST),请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。提醒一下, 二叉搜索树 满足下列约束条件:- 节点的左子树仅包含键 小于 节点键的节点。 - 节点的右子树仅包含键 大于 节点键的节点。 - 左右子树也必须是二叉搜索树。*示例 1:***![](/img/leetcode/

read more

105. 从前序与中序遍历序列构造二叉树

## 题目描述:给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。示例 1: ``` 输入: preorder = [3,9,20,15,7], inorder = [

read more

106. 从中序与后序遍历序列构造二叉树

## 题目描述:给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。示例 1: ``` 输入:inorder = [9,3,15,20,7], postorder

read more

109. 有序链表转换二叉搜索树

## 题目描述:给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。示例 1: ``` 输入: head = [-10,-3,0,5,9] 输出: [0,-3,9

read more

114. 二叉树展开为链表

## 题目描述:给你二叉树的根结点 root ,请你将它展开为一个单链表:- 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。 - 展开后的单链表应该与二叉树 先序遍历 顺序相同。示例 1: ``` 输入:root

read more