一题算法 | 字符串中的查找与替换

419 阅读3分钟

题目

对于某些字符串 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题

个人公众号