这道题一看就是使用回溯法,但是由于是排列,所以索引和组合不同(组合的索引是从start标志位开始),排列是从下标为0开始,并且需要借助排序!所以需要先转化成将String转化为char[]类型,然后借用Arrays类的sort函数进行排序,排除可能重复的项目。这里是参数出错:
这里错在List类型的变量判断长度是使用size函数。而且String类型的数组每个元素等于一个对String列表使用get()函数,然后将对应元素存进String数组中。
StringBuilder和StringBuffer的区别不仅只有速度和线程安全性的区别,还有调用函数的区别!delete是指定开始和结尾。
2023/8/24
这里一开始使用StringBuilder想来存结果不方便,因为StringBuilder存的信息是直接在结尾加上。所以要使用List来存储,然后再用List专有的get函数使用for循环一个个取出来。
这里要记住,List里可以存String类型的变量(泛型包括Integer,String,Character等)。然后将这个每次一个String(通过StringBuilder的toString()函数转化后)。千万记住最后创建String大小的时候是res的大小(有几个答案就创建几个空间)
List方法
List接口包括Collection接口的所有方法。 这是因为Collection是List的超级接口。
Collection接口中还提供了一些常用的List接口方法:
-
add() - 将元素添加到列表
-
addAll() - 将一个列表的所有元素添加到另一个
-
get() - 有助于从列表中随机访问元素
-
iterator() - 返回迭代器对象,该对象可用于顺序访问列表的元素
-
set() - 更改列表的元素
-
remove() - 从列表中删除一个元素
-
removeAll() - 从列表中删除所有元素
-
clear() - 从列表中删除所有元素(比removeAll()效率更高)
-
size() - 返回列表的长度
-
toArray() - 将列表转换为数组
-
contains() - 如果列表包含指定的元素,则返回true
当存储的临时空间长度满足目标长度时,就可以结束了并将这个存进结果集合了。如果不满足,就需要继续进行判断,如果当前值被访问过,或者当前值没有被访问过,但是前面的值也没有被访问过(说明这个循环已经结束)。保证相同的元素必须保持其相对顺序!!这就是为什么要将String类型的值转为CharArray然后进行排序,并且从左往右进行遍历的原因。然后在调用后复原visited和删除结尾的那个值(撤销),并且StringBuilder的撤销使用的是delete函数,第一个参数是开头位置,第二个是结尾位置,并且是左闭右开。
发现个比较神奇的点,就是在判断是否重复的时候,无论i>0 && !visited[i-1] && charArr[i]==charArr[i-1]中的条件visit[i-1]是访问过也好还是没访问过,其实都是可以得到答案的的。
当是!visited[i-1]时,说明没有被访问过,那么在第i个相同的元素是不能使用的,也就是官方题解中所说的,在最左边的相同元素使用了,后面的元素才能继续使用,这样就可以保证在左边的相同元素在所有排列中都是在左边的,比如说[a,b1,b2,c]出来的排列有[a,b1,b2,c],[a,b1,c,b2]....等等,但是不会出现[a,b2,b1,c],[a,b2,c,b1]这样的情况。也就是保证有序性,避免重复。
当是visited[i-1]时,说明被访问过了,那么为什么这样也能得到正确答案呢,是因为这样的条件是保证了首先排列最右边的相同元素,与上面恰好相反,这样的条件出来的排列会保证b2始终在b1左边。