这一题,其实弄明白了诀窍也不会很烦。关键在于说其实每一组结果,都可以提取到一个base case。
理由是这样的,就拿第一组来说,"abc" => "bcd" => "xyz"
其中,一个规律就是 b - a = c - b = d - c = 1。或者x - a = y - b = z - c = 23。也就是说bcd只要左shift一次,就可以是abc, xyz只要左shift 23次,就也可以是abc。 如果我们以字符串的第一个字符为a的字符串为这一组的base case。我们就只需要计算第一个字符和a的距离,你就知道整个字符串左shift多少次可以变成一个组的base case。然后我们用一个哈希表来维护组员。(组员可以不包括base case)
举个例子, abc, efg, bdf, efi
1.abc里,a 和 a 的距离是0,所以该字符串不需要左移,自己就是base case。哈希表里面就有了组abc, 然后成员为abc
2.efg里, e 和 a 的距离是4,所以该字符串需要整体左移4格,然后变成了abc这个base case,然后哈希表的abc组里面添加一个成员 efg
3. bdf,b和a的距离是1, 所以该字符串整体左移1个,变成了ace这个base case,哈希表里多了一个组ace,成员为bdf
4. efi,e和a的距离是4,所以整体左移4次,变成了ace,所以哈希表里的ace组再添加一员猛将efi。
至此添加完毕,每一个组的value部分就是题目所需要的列表解集。再注意一下避免左移过多造成的过范围,所以需要通过加26来避免。给出代码如下:
public List<List<String>> groupStrings(String[] strings) {
Map<String, List<String>> strMap = new HashMap<>();
for (String str : strings) {
String shiftedKey = _getShiftedString(str);
if (!strMap.containsKey(shiftedKey)) strMap.put(shiftedKey, new LinkedList<String>());
strMap.get(shiftedKey).add(str);
}
return new LinkedList<List<String>>(strMap.values());
}
private String _getShiftedString(String a) {
if (a.length() > 0) {
char[] cArr = a.toCharArray();
int diff = (int)cArr[0] - 'a';
cArr[0] = 'a';
for (int i = 1; i < cArr.length; i++) {
cArr[i] = (char)(((int)(cArr[i] - 'a') >= diff) ? (int)cArr[i] - diff : (int)cArr[i] - diff + 26);
}
return new String(cArr);
} else {
return a;
}
}