首页 > 其他分享 >2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“

2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“

时间:2023-05-23 21:31:38浏览次数:47  
标签:相等 int strs 相似 字符串 fi fj uf size

2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等,

那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。

例如,"tars" 和 "rats" 是相似的 (交换 0 与 2 的位置);

"rats" 和 "arts" 也是相似的,但是 "star" 不与 "tars","rats",或 "arts" 相似。

总之,它们通过相似性形成了两个关联组:{"tars", "rats", "arts"} 和 {"star"}。

注意,"tars" 和 "arts" 是在同一组中,即使它们并不相似。

形式上,对每个组而言,要确定一个单词在组中,只需要这个词和该组中至少一个单词相似。

给你一个字符串列表 strs。列表中的每个字符串都是 strs 中其它所有字符串的一个字母异位词。

请问 strs 中有多少个相似字符串组?

输入:strs = ["tars","rats","arts","star"]。

输出:2。

答案2023-05-23:

具体过程如下:

1.定义一个结构体 UnionFind,包含以下字段:

  • Father []int:每个元素的父节点;
  • Size []int:每个子集的大小;
  • Help []int:帮助数组;
  • Sets int:集合数量。

2.编写函数 NewUnionFind(n int) *UnionFind,创建一个新的并查集,需传入元素数量 n,实现如下:

  • 创建一个 UnionFind 结构体 uf,分别用 make 函数初始化父节点数组、子集大小数组和帮助数组,将集合数量 Sets 初始化为元素数量 n
  • 遍历每个元素,将其父节点初始化为自身,子集大小初始化为1。
  • 返回 uf

3.编写函数 Find(i int) int 实现路径压缩的查找操作,返回元素 i 所在集合的根节点,具体步骤如下:

  • 定义辅助变量 hi 为0;
  • 如果元素 i 的父节点不是它本身,将 i 加入帮助数组,将 i 更新为其父节点;
  • i 的父节点等于它本身时,表明已经到达集合的根节点,遍历帮助数组,依次将这些元素的父节点更新为根节点;
  • 返回根节点。

4.编写函数 Union(i, j int) 实现按秩合并的操作,将元素 i 所在集合和元素 j 所在集合合并成一个集合,具体步骤如下:

  • 分别查找元素 i 和元素 j 所在集合的根节点,如果它们所在的集合已经相同,则不需要合并;
  • 否则,比较两个集合的大小,将小的集合合并到大的集合中,并更新父节点和子集大小,同时将集合数量减1。

5.编写函数 Sets0() int 返回当前并查集中集合的数量,直接返回结构体字段 Sets 的值即可。

6.编写函数 numSimilarGroups(strs []string) int,遍历每对字符串,如果它们属于不同的集合,判断它们是否相似,如果是相似的则将它们合并到同一个集合中,最终返回并查集中剩余的集合数量,具体步骤如下:

  • 创建一个新的并查集 uf,元素数量为输入字符串列表 strs 的长度;
  • 遍历输入字符串列表 strs,对于每一对字符串 s1s2,判断它们是否属于同一个集合,如果不是,则比较它们是否相似,如果是相似的,则将它们所在集合合并;
  • 返回并查集中集合的数量。

7.在 main 函数中,给定输入字符串列表 strs,调用 numSimilarGroups 函数计算相似字符串组的数量,并输出结果。

时间复杂度:在最坏情况下,需要枚举任意两个字符串进行比较,因此需要 2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“_并查集 的时间复杂度,其中 2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“_并查集_02 是字符串数组 strs 中字符串的数量,2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“_字符串_03 是字符串的长度。并查集合并操作的时间复杂度为 2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“_i++_04,其中 2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“_i++_04 是反阿克曼函数的某个很小的值,可以看作是常数级别的时间复杂度,因此对总时间复杂度的贡献可以忽略不计。因此,最终的时间复杂度为 2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“_并查集

空间复杂度:主要由并查集所用的空间和额外的辅助变量所占用的空间构成。其中,并查集需要的空间是 2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“_并查集_07,辅助变量 Help 需要的空间也是 2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“_并查集_07,因此总的空间复杂度为 2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“_并查集_07

go语言完整代码如下:

package main

import "fmt"

func numSimilarGroups(strs []string) int {
	n, m := len(strs), len(strs[0])
	uf := NewUnionFind(n)
	for i := 0; i < n; i++ {
		for j := i + 1; j < n; j++ {
			if uf.Find(i) != uf.Find(j) {
				diff := 0
				for k := 0; k < m && diff < 3; k++ {
					if strs[i][k] != strs[j][k] {
						diff++
					}
				}
				if diff == 0 || diff == 2 {
					uf.Union(i, j)
				}
			}
		}
	}
	return uf.Sets0()
}

type UnionFind struct {
	Father []int
	Size   []int
	Sets   int
	Help   []int
}

func NewUnionFind(n int) *UnionFind {
	uf := &UnionFind{
		Father: make([]int, n),
		Size:   make([]int, n),
		Help:   make([]int, n),
		Sets:   n,
	}
	for i := 0; i < n; i++ {
		uf.Father[i] = i
		uf.Size[i] = 1
	}
	return uf
}

func (uf *UnionFind) Find(i int) int {
	hi := 0
	for i != uf.Father[i] {
		uf.Help[hi] = i
		hi++
		i = uf.Father[i]
	}
	for hi > 0 {
		hi--
		uf.Father[uf.Help[hi]] = i
	}
	return i
}

func (uf *UnionFind) Union(i, j int) {
	fi, fj := uf.Find(i), uf.Find(j)
	if fi != fj {
		if uf.Size[fi] >= uf.Size[fj] {
			uf.Father[fj] = fi
			uf.Size[fi] += uf.Size[fj]
		} else {
			uf.Father[fi] = fj
			uf.Size[fj] += uf.Size[fi]
		}
		uf.Sets--
	}
}

func (uf *UnionFind) Sets0() int {
	return uf.Sets
}

func main() {
	strs := []string{"tars", "rats", "arts", "star"}
	res := numSimilarGroups(strs)
	fmt.Println(res)
}

2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“_i++_10

rust完整代码如下:

fn main() {
    let strs = vec![
        "tars".to_string(),
        "rats".to_string(),
        "arts".to_string(),
        "star".to_string(),
    ];
    let res = num_similar_groups(strs);
    println!("{}", res);
}

fn num_similar_groups(strs: Vec<String>) -> i32 {
    let n = strs.len();
    let m = strs[0].len();
    let mut uf = UnionFind::new(n);
    for i in 0..n {
        for j in i + 1..n {
            // [i] [j]
            if uf.find(i) != uf.find(j) {
                let mut diff = 0;
                for k in 0..m {
                    if strs[i].as_bytes()[k] != strs[j].as_bytes()[k] {
                        diff += 1;
                    }
                    if diff >= 3 {
                        break;
                    }
                }
                if diff == 0 || diff == 2 {
                    uf.union(i, j);
                }
            }
        }
    }
    uf.sets() as i32
}

struct UnionFind {
    father: Vec<usize>,
    size: Vec<i32>,
    help: Vec<usize>, // 添加help字段
    sets: usize,
}

impl UnionFind {
    fn new(n: usize) -> Self {
        let mut father = vec![0; n];
        let size = vec![1; n];
        for i in 0..n {
            father[i] = i;
        }
        Self {
            father,
            size,
            help: vec![0; n], // 初始化help
            sets: n,
        }
    }

    fn find(&mut self, i: usize) -> usize {
        let mut hi = 0;
        let mut j = i;
        while j != self.father[j] {
            self.help[hi] = j;
            hi += 1;
            j = self.father[j];
        }
        while hi > 0 {
            hi -= 1;
            self.father[self.help[hi]] = j;
        }
        j
    }

    fn union(&mut self, i: usize, j: usize) {
        let fi = self.find(i);
        let fj = self.find(j);
        if fi != fj {
            if self.size[fi] >= self.size[fj] {
                self.father[fj] = fi;
                self.size[fi] += self.size[fj];
            } else {
                self.father[fi] = fj;
                self.size[fj] += self.size[fi];
            }
            self.sets -= 1;
        }
    }

    fn sets(&self) -> usize {
        self.sets
    }
}

2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“_字符串_11

c语言完整代码如下:

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

typedef struct {
    int* father;
    int* size;
    int* help;
    int sets;
} UnionFind;

UnionFind* newUnionFind(int n) {
    UnionFind* uf = (UnionFind*)malloc(sizeof(UnionFind));
    uf->father = (int*)malloc(sizeof(int) * n);
    uf->size = (int*)malloc(sizeof(int) * n);
    uf->help = (int*)malloc(sizeof(int) * n);
    for (int i = 0; i < n; i++) {
        uf->father[i] = i;
        uf->size[i] = 1;
    }
    uf->sets = n;
    return uf;
}

int find(UnionFind* uf, int i) {
    int hi = 0;
    while (i != uf->father[i]) {
        uf->help[hi++] = i;
        i = uf->father[i];
    }
    while (hi != 0) {
        hi--;
        uf->father[uf->help[hi]] = i;
    }
    return i;
}

void unionSet(UnionFind* uf, int i, int j) {
    int fi = find(uf, i);
    int fj = find(uf, j);
    if (fi != fj) {
        if (uf->size[fi] >= uf->size[fj]) {
            uf->father[fj] = fi;
            uf->size[fi] += uf->size[fj];
        }
        else {
            uf->father[fi] = fj;
            uf->size[fj] += uf->size[fi];
        }
        uf->sets--;
    }
}

int getSets(UnionFind* uf) {
    return uf->sets;
}

int numSimilarGroups(char** strs, int strsSize) {
    int n = strsSize, m = strlen(strs[0]);
    UnionFind* uf = newUnionFind(n);
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            if (find(uf, i) != find(uf, j)) {
                int diff = 0;
                for (int k = 0; k < m && diff < 3; k++) {
                    if (strs[i][k] != strs[j][k]) {
                        diff++;
                    }
                }
                if (diff == 0 || diff == 2) {
                    unionSet(uf, i, j);
                }
            }
        }
    }
    return getSets(uf);
}

int main() {
    char* strs[] = { "tars", "rats", "arts", "star" };
    int strsSize = sizeof(strs) / sizeof(strs[0]);
    int res = numSimilarGroups(strs, strsSize);
    printf("%d\n", res); // 输出 2
    return 0;
}

2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“_并查集_12

c++完整代码如下:

#include <iostream>
#include <vector>
using namespace std;

class UnionFind {
public:
    vector<int> father;
    vector<int> size;
    vector<int> help;
    int sets;

    UnionFind(int n) : father(n), size(n, 1), help(n), sets(n) {
        for (int i = 0; i < n; i++) {
            father[i] = i;
        }
    }

    int find(int i) {
        int hi = 0;
        while (i != father[i]) {
            help[hi++] = i;
            i = father[i];
        }
        while (hi != 0) {
            father[help[--hi]] = i;
        }
        return i;
    }

    void unionSet(int i, int j) {
        int fi = find(i);
        int fj = find(j);
        if (fi != fj) {
            if (size[fi] >= size[fj]) {
                father[fj] = fi;
                size[fi] += size[fj];
            }
            else {
                father[fi] = fj;
                size[fj] += size[fi];
            }
            sets--;
        }
    }

    int getSets() {
        return sets;
    }
};

int numSimilarGroups(vector<string>& strs) {
    int n = strs.size(), m = strs[0].size();
    UnionFind uf(n);
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            if (uf.find(i) != uf.find(j)) {
                int diff = 0;
                for (int k = 0; k < m && diff < 3; k++) {
                    if (strs[i][k] != strs[j][k]) {
                        diff++;
                    }
                }
                if (diff == 0 || diff == 2) {
                    uf.unionSet(i, j);
                }
            }
        }
    }
    return uf.getSets();
}

int main() {
    vector<string> strs = { "tars", "rats", "arts", "star" };
    int res = numSimilarGroups(strs);
    cout << res << endl;
    return 0;
}

2023-05-23:如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等, 那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。 例如,“tars“_并查集_13

标签:相等,int,strs,相似,字符串,fi,fj,uf,size
From: https://blog.51cto.com/moonfdd/6334817

相关文章

  • 字符串、列表内置方法和可变类型、不可变类型
    字符串的内置方法1.转换大小写(upper、lower)将字符串中的所有单词转换成大写或者小写,name_str.upper()  将name_str中的字母全转换为大写name_str.lower() 将name_str中的字母全转换为大写例:1name_str="helloword"2res=name_str.upper()3print(res)......
  • html转义代码,v-html 显示原始html字符串
    methods:  htmlEscape(str){   lets="";   if(str.length==0)return"";   s=str.replace(/&/g,"&amp;");   s=s.replace(/</g,"<");   s=s.replace(/>/g,">");......
  • 图解LeetCode——1460. 通过翻转子数组使两个数组相等(难度:简单)
    一、题目给你两个长度相同的整数数组 target 和 arr 。每一步中,你可以选择 arr 的任意非空子数组 并将它翻转。你可以执行此过程任意次。如果你能让arr 变得与target 相同,返回True;否则,返回False。二、示例2.1>示例1:【输入】target=[1,2,3,4],arr=[2,4,1,3]......
  • 图解LeetCode——1224. 最大相等频率(难度:困难)
    一、题目给你一个正整数数组 nums,请你帮忙从该数组中找出能满足下面要求的最长前缀,并返回该前缀的长度:从前缀中恰好删除一个元素后,剩下每个数字的出现次数都相同。如果删除这个元素后没有剩余元素存在,仍可认为每个数字都具有相同的出现次数(也就是0次)。二、示例2.1>示例1:【......
  • 代码随想录算法训练营第9天 | ●28. 实现 strStr() ●459.重复的子字符串 ●字符串总
     第四章 字符串part02今日任务  ● 28. 实现 strStr()● 459.重复的子字符串● 字符串总结 ● 双指针回顾   详细布置  28. 实现 strStr()  (本题可以跳过) 因为KMP算法很难,大家别奢求 一次就把kmp全理解了,大家刚学KMP一定会有各种各样的疑问......
  • 代码随想录算法训练营第11天 | ● 20. 有效的括号 ● 1047. 删除字符串中的所有相邻重
     第五章 栈与队列part02今日内容:  ●  20. 有效的括号●  1047. 删除字符串中的所有相邻重复项●  150. 逆波兰表达式求值  详细布置   20. 有效的括号  讲完了栈实现队列,队列实现栈,接下来就是栈的经典应用了。  大家先自己思考一下 有......
  • 5.22 字符串专题模拟赛
    T1P7469[NOIOnline2021提高组]积木小赛签到题,考虑固定\(\texttt{Bob}\)的左端点,双指针去判断是否匹配即可,时间复杂度\(O(n^2)\)。T2P7114[NOIP2020]字符串匹配考虑到\(AB\)必然是一个前缀,枚举\(AB\)长度\(len\),\(C\)的长度只有\(\lfloor\dfrac{n-len}{l......
  • 2023-05-22:给定一个长度为 n 的字符串 s ,其中 s[i] 是: D 意味着减少; I 意味着增加。
    2023-05-22:给定一个长度为n的字符串s,其中s[i]是:D意味着减少;I意味着增加。有效排列是对有n+1个在[0,n]范围内的整数的一个排列perm,使得对所有的i:如果s[i]=='D',那么perm[i]>perm[i+1],以及;如果s[i]=='I',那么perm[i]<perm[i+1]。返回有效排列......
  • Linux 使用grep过滤字符串中的指定内容
    命令示例:echoport1234123|grep-oP'port\s+\K\d+'返回:1234这条命令使用grep工具来在文本中查找"Port"后面跟着一个或多个空格的数字,并使用-oP标志来仅显示匹配的数字而不是整个行。其中\K是一个正则表达式的零宽度断言,表示从此处开始匹配,但不包括前面的字符......
  • JAVA 截取字符串的三种方法 subString,StringUtils,split
    JAVA截取字符串的三种方法subString,StringUtils,split主要有以下几种方法:1、通过subString()方法来进行字符串截取(最常用)2、通过StringUtils提供的方法3、split()+正则表达式来进行截取 1、通过subString()方法来进行字符串截取,返回字符串中的子字符串,在java中有两种用......