算法总结 - 字符串 - 字符转换

1153. String Transforms Into Another String

题目链接
Given two strings str1 and str2 of the same length, determine whether you can transform str1 into str2 by doing zero or more conversions.

In one conversion you can convert all occurrences of one character in str1 to any other lowercase English character.

Return true if and only if you can transform str1 into str2.

Example 1:

Input: str1 = “aabcc”, str2 = “ccdee”
Output: true
Explanation: Convert ‘c’ to ‘e’ then ‘b’ to ‘d’ then ‘a’ to ‘c’. Note that the order of conversions matter.
Example 2:

Input: str1 = “leetcode”, str2 = “codeleet”
Output: false
Explanation: There is no way to transform str1 to str2.

Note:

1 <= str1.length == str2.length <= 10^4
Both str1 and str2 contain only lowercase English letters.


Abstract

  • 给出两个字符串str1 和 str2,判断字符串 str1 能不能在 零次 或 多次 转化后变成 str2

  • 每一次转化时,将会一次性将 str1 中出现的所有相同字母变成其他任何小写英文字母

Idea
用一个map记录每个字母第一次转化的情况,如果后续碰到同样的字符却发现转化成的字母不符合map记录的情况则说明转化有冲突

Question to ask

  • 一个字母被转化成多个字母情况出现时该怎么办?
  • 如果有环怎么办?
  • 如果一个字母没有转化(outgoing edge)怎么处理?

Solution

  • 用一个map记录每个字母第一次转化的情况,如果后续碰到同样的字符却发现转化成的字母不符合map记录的情况则说明转化有冲突
  • 如果转化可以发生,那么必须有一个字母充当转化的中建桥梁:
    • 比如 a -> b -> c, 字母b就是中间桥梁,所以26个字母中至少有一个字母是不会发生转化的

Code

public boolean canConvert(String str1, String str2) {
    Map<Character, Character> map = new HashMap<>();
    
    if (str1.length() != str2.length()) return false;
    if (str1.equals(str2)) return true;
    
    Set<Character> vis = new HashSet<>();
    
    for (int i = 0; i < str1.length(); i++){
        char c1 = str1.charAt(i);
        char c2 = str2.charAt(i);
        // m1
        vis.add(c2);
        if (map.containsKey(c1)){
            if (map.get(c1) != c2){
                return false;
            }
        }else{
            map.put(c1, c2);
        }
    }
    
    return true;
}

Time Complexity
O (n)

Space Complexity
O(26)

Mistake

  1. 没有坚持26个字母都被转化的情况

Summary

  • 转化和图的问题一定要处理环

833. Find And Replace in String

To some string S, we will perform some replacement operations that replace groups of letters with new ones (not necessarily the same size).

Each replacement operation has 3 parameters: a starting index i, a source word x and a target word y. The rule is that if x starts at position i in the original string S, then we will replace that occurrence of x with y. If not, we do nothing.

For example, if we have S = “abcd” and we have some replacement operation i = 2, x = “cd”, y = “ffff”, then because “cd” starts at position 2 in the original string S, we will replace it with “ffff”.

Using another example on S = “abcd”, if we have both the replacement operation i = 0, x = “ab”, y = “eee”, as well as another replacement operation i = 2, x = “ec”, y = “ffff”, this second operation does nothing because in the original string S[2] = ‘c’, which doesn’t match x[0] = ‘e’.

All these operations occur simultaneously. It’s guaranteed that there won’t be any overlap in replacement: for example, S = “abc”, indexes = [0, 1], sources = [“ab”,“bc”] is not a valid test case.

Example 1:

Input: S = “abcd”, indexes = [0,2], sources = [“a”,“cd”], targets = [“eee”,“ffff”]
Output: “eeebffff”
Explanation: “a” starts at index 0 in S, so it’s replaced by “eee”.
“cd” starts at index 2 in S, so it’s replaced by “ffff”.
Example 2:

Input: S = “abcd”, indexes = [0,2], sources = [“ab”,“ec”], targets = [“eee”,“ffff”]
Output: “eeecd”
Explanation: “ab” starts at index 0 in S, so it’s replaced by “eee”.
“ec” doesn’t starts at index 2 in the original S, so we do nothing.
Notes:

0 <= indexes.length = sources.length = targets.length <= 100
0 < indexes[i] < S.length <= 1000
All characters in given inputs are lowercase letters.


Abstract

  • 给一个字符串S,可能替换元素的位置数组indexes,需要被替换的字符串数组和替换后的字符串数组
  • 判断S在可能替换的位置是否存在可以被替换的字符串,如果有则替换成目标字符串

Idea

  • 依次检查可能替换元素的位置是否存在可替换元素并替换

Question to ask

  • 由于被替换字符串的长度可能与目标字符串的长度不同,那么怎么确保在替换后还能跟踪原字符的位置?

Solution

  • 可以由后向前检查S中可被替换的元素并在同时进行替换,这样替换后字符串的长度并不会对S前半部分产生影响

Code

public String findReplaceString(String S, int[] indexes, String[] sources, String[] targets) {
    
    int[][] sort = new int[sources.length][2];
    
    for (int i = 0; i < indexes.length; i++){
        sort[i][0] = indexes[i];
        sort[i][1] = i;
    }
    
    
    Arrays.sort(sort, (a, b) -> b[0] - a[0]);

    int k = 0;
    
    for (int i = S.length(); i >= 0; i --){
        if (k < sort.length && i == sort[k][0]){
            String orig = sources[sort[k][1]];
            String target = targets[sort[k][1]];
            
            if (S.substring(i, i + orig.length()).equals(orig)){
                S = S.substring(0, i) + target + S.substring(i + orig.length());
            }
            k++;
        }
    }
    
    return S;
}

Time Complexity
O(n)

Space Complexity
O(1)

Mistake
None

Summary

  • 注意逆向思维
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值