题目
对于某些字符串 S,我们将执行一些替换操作,用新的字母组替换原有的字母组(不一定大小相同)。 每个替换操作具有 3 个参数:起始索引 i,源字 x 和目标字 y。规则是如果 x 从原始字符串 S 中的位置 i 开始,那么我们将用 y 替换出现的 x。如果没有,我们什么都不做。
示例
输入:S = "abcd", indexes = [0,2], sources = ["a","cd"], targets = ["eee","ffff"]
输出:"eeebffff"
解释:
"a" 从 S 中的索引 0 开始,所以它被替换为 "eee"。
"cd" 从 S 中的索引 2 开始,所以它被替换为 "ffff"
提示
0 <= indexes.length = sources.length = targets.length <= 100
0 < indexes[i] < S.length <= 1000
给定输入中的所有字符都是小写字母
解题思路
解法一
先找出需要替换的索引replace_indexs,然后对replace_indexs进行排序,为什么需要排序呢?因为替换值和被替换值的长度不一样,这样就产生了偏移量offset,因为原indexes是无序的,偏移量影响的地方不确定,当对replace_indexs排序后,偏移量只会对后面的需要替换的字符串造成影响,在字符串截取或者替换的时候,开始坐标就变成了index+offset。
解法二
将原字符串转换成char数组,每个下标对应一个标记是否需要字符串替换。遍历整个char数组,将每个值添加到新的字符串中,如果需要替换,添加的值为替换值,下标变换等于原下标+被替换字符串的长度。如果不需要替换,添加值为char数组对应下标的值,下标前移一位。
代码实现
方法一
/**
* 将需要替换的索引排序,因为替换的值和被替换值得长度不一样,所以在字符串截取的时候会产生偏移量,将需要替换的索引排序后,偏移量只会对后面需要替换的字符串产生影响
*
* @param S
* @param indexes
* @param sources
* @param targets
* @return
*/
public static String findReplaceStringByOrderIndex(String S, int[] indexes, String[] sources, String[] targets) {
StringBuilder sb = new StringBuilder(S);
// new 一个具有排序功能的TreeMap
Map<Integer, Integer> map = new TreeMap<Integer, Integer>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
// 查找出需要替换的字符串存入map,key为需要替换字符串的下标,value为原数组下标
for (int i = 0; i < indexes.length; i++) {
int index = indexes[i];
String source = sources[i];
// 判断是否需要替换
if (S.substring(index).startsWith(source)) {
map.put(index, i);
}
}
// 偏移量
int offset = 0;
for (Integer key : map.keySet()) {
Integer value = map.get(key);
String source = sources[value];
String target = targets[value];
sb.replace(key + offset, key + offset + source.length(), target);
offset += target.length() - source.length();
}
return sb.toString();
}
方法二
/**
* 将字符串转变成char数组,逐个添加到新字符串中
* @param S
* @param indexes
* @param sources
* @param targets
* @return
*/
public static String findReplaceStringByCharAt(String S, int[] indexes, String[] sources, String[] targets) {
StringBuilder sb = new StringBuilder();
// 新建一个S.length()长度的数组,初始值为-1,需要替换的地方将数组的值置为indexs数组的下标。
int[] hash = new int[S.length()];
Arrays.fill(hash, -1);
for (int i = 0; i < indexes.length; i++) {
int idx = indexes[i];
if (S.indexOf(sources[i], indexes[i]) == indexes[i]) {
hash[idx] = i;
}
}
// 查找出需要替换的字符串存入map,Map效率没有数组高
// Map<Integer, Integer> replaceMap = new HashMap<>();
// for (int i = 0; i < indexes.length; i++) {
// int index = indexes[i];
// if (S.indexOf(sources[i],index)==index) {
// replaceMap.put(index, i);
// }
// }
// 遍历字符串,将字符串转换为字节,添加到StringBuilder的中,需要替换的地方将原来的值替换掉
for (int i = 0; i < S.length(); ) {
if (hash[i] >= 0) {
sb.append(targets[hash[i]]);
i += sources[hash[i]].length();
} else {
sb.append(S.charAt(i));
i++;
}
}
return sb.toString();
}
题目来源:
leetcode833题