Anagram 递归 Scala
Anagram Recursion Scala
这是我尝试编写代码的问题。
考虑一个递归算法,它将两个字符串 s1 和 s2 作为输入,并检查这些字符串是否是彼此的字谜,因此如果前者中包含的所有字母在后者中出现的次数相同,反之亦然(即 s2 是 s1 的排列).
示例:
如果 s1 = ”elevenplustwo” 和 s2 = ”twelveplusone” 输出为真
如果 s1 = ”amina” 和 s2 = ”minia” 输出为 false
提示: 考虑s1的第一个字符c = s1(0)和r的其余字符=s1.substring(1, s1.size) 的 s1。 s2 必须(递归地)满足关于 c 和 r 的条件是什么?
这是我为解决这个问题而写的一段代码。问题是当字符串中没有重复的字符时,代码可以完美运行。例如,它适用于 amin 和 mina。但是,当出现重复时,例如amina和maina,则无法正常工作。
我该如何解决这个问题?
import scala.collection.mutable.ArrayBuffer
object Q32019 extends App {
def anagram(s1:String, s2:String, indexAr:ArrayBuffer[Int]):ArrayBuffer[Int]={
if(s1==""){
return indexAr
}
else {
val c=s1(0)
val s=s1.substring(1,s1.length)
val ss=s2
var count=0
for (i<-0 to s2.length-1) {
if(s2(i)==c && !indexAr.contains(s2.indexOf(c))) {
indexAr+=i
}
}
anagram(s,s2,indexAr)
}
indexAr
}
var a="amin"
var b="mina"
var c=ArrayBuffer[Int]()
var d=anagram(a,b,c)
println(d)
var check=true
var i=0
while (i<a.length && check){
if (d.contains(i) && a.length==b.length) check=true
else check=false
i+=1
}
if (check) println("yes they are anagram")
else println("no, they are not anagram")
}
最简单的方法可能是对两个字符串进行排序并比较它们:
def areAnagram(str1: String, str2: String): Boolean =
str1.sorted == str2.sorted
println(areAnagram("amina", "anima")) // true
println(areAnagram("abc", "bcc")) // false
另外一个多"natural"。如果两个字符串 每个字符的数量相同 .
,则它们是变位词
所以你做了两个 Map[Char, Int]
并比较它们:
import scala.collection.mutable
def areAnagram(str1: String, str2: String): Boolean = {
val map1 = mutable.Map.empty[Char, Int].withDefaultValue(0)
val map2 = mutable.Map.empty[Char, Int].withDefaultValue(0)
for (c <- str1) map1(c) += 1
for (c <- str2) map2(c) += 1
map1 == map2
}
如果您知道字符只是 ASCII 字符,那么还有另一个版本的第二个解决方案可能带有 Array
s。
或者其他一些聪明的算法,IDK。
编辑:一个递归解决方案可能是从 str2[=36= 中删除 str1 的第一个字符].两个字符串的其余部分也必须是变位词。
例如。对于 ("amina", "niama")
首先你从两者中抛出一个 a
,然后你得到 ("mina", "nima")
。根据定义,这 2 个字符串 也必须是字谜 。
def areAnagram(str1: String, str2: String): Boolean = {
if (str1.length != str2.length) false
else if (str1.isEmpty) true // end recursion
else {
val (c, r1) = str1.splitAt(1)
val r2 = str2.replaceFirst(c, "") // remove c
areAnagram(r1, r2)
}
}
当您计算字谜时,您可以利用 XOR 运算的 属性,也就是说,如果您对两个相同的数字进行异或,您将得到 0。
由于字符串中的字符本质上只是数字,您可以 运行 对两个字符串的所有字符进行异或,如果结果为 0,则这些字符串是变位词。
您可以使用循环遍历两个字符串,但如果您想使用递归,我建议您将字符串转换为字符列表。
列表允许在第一个元素(列表头部)和其余元素(列表尾部)之间进行有效拆分。所以解决方案是这样的:
- 将两个字符列表的列表拆分为头部和尾部。
- 运行 对从列表头部和先前结果中提取的字符进行异或运算。
- 将列表尾部和异或结果传递给下一个递归调用。
当我们到达列表的末尾时,我们只是 return true 异或运算的结果是 0。
我们可以做的最后优化是在传递不同长度的字符串时使用 false 缩短(因为它们永远不可能是字谜)。
最终解决方案:
def anagram(a: String, b: String): Boolean = {
//inner function doing recursion, annotation @tailrec makes sure function is tail-recursive
@tailrec
def go(a: List[Char], b: List[Char], acc: Int): Boolean = { //using additional parameter acc, allows us to use tail-recursion, which is safe for stack
(a, b) match {
case (x :: xs, y :: ys) => //operator :: splits list to head and tail
go(xs, ys, acc ^ x ^ y) //because we changed string to lists of chars, we can now efficiently access heads (first elements) of lists
//we get first characters of both lists, then call recursively go passing tails of lists and result of xoring accumulator with both characters
case _ => acc == 0 //if result of xoring whole strings is 0, then both strings are anagrams
}
}
if (a.length != b.length) { //we already know strings can't be anagrams, because they've got different size
false
} else {
go(a.toList, b.toList, 0)
}
}
anagram("twelveplusone", "elevenplustwo") //true
anagram("amina", "minia") //false
我的建议:不要想太多。
def anagram(a: String, b: String): Boolean =
if (a.isEmpty) b.isEmpty
else b.contains(a(0)) && anagram(a.tail, b diff a(0).toString)
这是我尝试编写代码的问题。
考虑一个递归算法,它将两个字符串 s1 和 s2 作为输入,并检查这些字符串是否是彼此的字谜,因此如果前者中包含的所有字母在后者中出现的次数相同,反之亦然(即 s2 是 s1 的排列).
示例:
如果 s1 = ”elevenplustwo” 和 s2 = ”twelveplusone” 输出为真
如果 s1 = ”amina” 和 s2 = ”minia” 输出为 false
提示: 考虑s1的第一个字符c = s1(0)和r的其余字符=s1.substring(1, s1.size) 的 s1。 s2 必须(递归地)满足关于 c 和 r 的条件是什么?
这是我为解决这个问题而写的一段代码。问题是当字符串中没有重复的字符时,代码可以完美运行。例如,它适用于 amin 和 mina。但是,当出现重复时,例如amina和maina,则无法正常工作。
我该如何解决这个问题?
import scala.collection.mutable.ArrayBuffer
object Q32019 extends App {
def anagram(s1:String, s2:String, indexAr:ArrayBuffer[Int]):ArrayBuffer[Int]={
if(s1==""){
return indexAr
}
else {
val c=s1(0)
val s=s1.substring(1,s1.length)
val ss=s2
var count=0
for (i<-0 to s2.length-1) {
if(s2(i)==c && !indexAr.contains(s2.indexOf(c))) {
indexAr+=i
}
}
anagram(s,s2,indexAr)
}
indexAr
}
var a="amin"
var b="mina"
var c=ArrayBuffer[Int]()
var d=anagram(a,b,c)
println(d)
var check=true
var i=0
while (i<a.length && check){
if (d.contains(i) && a.length==b.length) check=true
else check=false
i+=1
}
if (check) println("yes they are anagram")
else println("no, they are not anagram")
}
最简单的方法可能是对两个字符串进行排序并比较它们:
def areAnagram(str1: String, str2: String): Boolean =
str1.sorted == str2.sorted
println(areAnagram("amina", "anima")) // true
println(areAnagram("abc", "bcc")) // false
另外一个多"natural"。如果两个字符串 每个字符的数量相同 .
,则它们是变位词
所以你做了两个 Map[Char, Int]
并比较它们:
import scala.collection.mutable
def areAnagram(str1: String, str2: String): Boolean = {
val map1 = mutable.Map.empty[Char, Int].withDefaultValue(0)
val map2 = mutable.Map.empty[Char, Int].withDefaultValue(0)
for (c <- str1) map1(c) += 1
for (c <- str2) map2(c) += 1
map1 == map2
}
如果您知道字符只是 ASCII 字符,那么还有另一个版本的第二个解决方案可能带有 Array
s。
或者其他一些聪明的算法,IDK。
编辑:一个递归解决方案可能是从 str2[=36= 中删除 str1 的第一个字符].两个字符串的其余部分也必须是变位词。
例如。对于 ("amina", "niama")
首先你从两者中抛出一个 a
,然后你得到 ("mina", "nima")
。根据定义,这 2 个字符串 也必须是字谜 。
def areAnagram(str1: String, str2: String): Boolean = {
if (str1.length != str2.length) false
else if (str1.isEmpty) true // end recursion
else {
val (c, r1) = str1.splitAt(1)
val r2 = str2.replaceFirst(c, "") // remove c
areAnagram(r1, r2)
}
}
当您计算字谜时,您可以利用 XOR 运算的 属性,也就是说,如果您对两个相同的数字进行异或,您将得到 0。
由于字符串中的字符本质上只是数字,您可以 运行 对两个字符串的所有字符进行异或,如果结果为 0,则这些字符串是变位词。
您可以使用循环遍历两个字符串,但如果您想使用递归,我建议您将字符串转换为字符列表。
列表允许在第一个元素(列表头部)和其余元素(列表尾部)之间进行有效拆分。所以解决方案是这样的:
- 将两个字符列表的列表拆分为头部和尾部。
- 运行 对从列表头部和先前结果中提取的字符进行异或运算。
- 将列表尾部和异或结果传递给下一个递归调用。
当我们到达列表的末尾时,我们只是 return true 异或运算的结果是 0。
我们可以做的最后优化是在传递不同长度的字符串时使用 false 缩短(因为它们永远不可能是字谜)。
最终解决方案:
def anagram(a: String, b: String): Boolean = {
//inner function doing recursion, annotation @tailrec makes sure function is tail-recursive
@tailrec
def go(a: List[Char], b: List[Char], acc: Int): Boolean = { //using additional parameter acc, allows us to use tail-recursion, which is safe for stack
(a, b) match {
case (x :: xs, y :: ys) => //operator :: splits list to head and tail
go(xs, ys, acc ^ x ^ y) //because we changed string to lists of chars, we can now efficiently access heads (first elements) of lists
//we get first characters of both lists, then call recursively go passing tails of lists and result of xoring accumulator with both characters
case _ => acc == 0 //if result of xoring whole strings is 0, then both strings are anagrams
}
}
if (a.length != b.length) { //we already know strings can't be anagrams, because they've got different size
false
} else {
go(a.toList, b.toList, 0)
}
}
anagram("twelveplusone", "elevenplustwo") //true
anagram("amina", "minia") //false
我的建议:不要想太多。
def anagram(a: String, b: String): Boolean =
if (a.isEmpty) b.isEmpty
else b.contains(a(0)) && anagram(a.tail, b diff a(0).toString)