LeetCode 205. Isomorphic Strings

题目

Given two strings s and t, determine if they are isomorphic.

Two strings are isomorphic if the characters in s can be replaced to get t.

All occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character but a character may map to itself.

Example 1:

Input: s = "egg", t = "add"
Output: true

Example 2:

Input: s = "foo", t = "bar"
Output: false

Example 3:

Input: s = "paper", t = "title"
Output: true

Note:
You may assume both and have the same length.


这道题要求两个字符串有没有相同的pattern,并且要一个字母只map一个字母,而且是双向的map。

思路很自然的想到了用map存储每个字母对应的新字母,然后用C++实现了一下,submit发现WA卡在了"ab", "aa"这一个test case上。在第一个字符时a映射到a,而第二个字符b也映射到a,这就不对了。然鹅,unordered_map并不提供直接查找value的操作(搜了一下好像没搜到?),于是想用C++写的话就必须得自己造个数据结构了(羡慕隔壁Java玩家)。

然后就看了一下discussion,模仿着自己造了两个长度为128的数组,初始化为0,用来存放每一个ASCII字符对应的mapping字符,并且两个数组是对称的,比如现在遇到了s: egg和t: add,那么在关于s的数组里要存放e对应的是a,并在关于t的数组里存放a对应的是e。每次循环时判断当前这个字符在不在两个数组里,不在就加进去,在的话如果两边对应关系不一致就return false。代码的复杂度是O(n),运行时间8ms,86.83%,空间复杂度O(n),9.1M,92%:

class Solution {
public:
    bool isIsomorphic(string s, string t) {
        char s_char[128] = {0};
        char t_char[128] = {0};
        
        for (int i = 0; i < s.length(); i++) {
            if (s_char[s[i]] == 0 && t_char[t[i]] == 0) {
                s_char[s[i]] = t[i];
                t_char[t[i]] = s[i];
            }
            else {
                if (s_char[s[i]] != t[i] || t_char[t[i]] != s[i]) {
                    return false;
                }
            }
        }
        return true;
    }
};

就,还是不会做呗,其实挺简单一题,但就是脑子不好使。两个string各自对应一个长度为ASCII code长度的数组,然后在各自字符对应的位置存下另一个string上对应的字符。如果两个对不上,就return false。

class Solution {
    public boolean isIsomorphic(String s, String t) {
        int[] map1 = new int[256];
        Arrays.fill(map1, -1);
        int[] map2 = new int[256];
        Arrays.fill(map2, -1);
        
        for (int i = 0; i < s.length(); i++) {
            char sc = s.charAt(i);
            char tc = t.charAt(i);
            if (map1[sc] == -1 && map2[tc] == -1) {
                map1[sc] = tc;
                map2[tc] = sc;
            } else if (map1[sc] != tc || map2[tc] != sc) {
                return false;
            }
        }
        return true;
    }
}

上面这种做法是一种非常非常传统的想法,还有另一种改进版就比较有技巧性,不是死板地把一个char map到另一个char。它的思想是把每个字母map到一个index,这个index就是这个字母第一次出现的位置,对两个string都是一样的操作。在遍历整个string的时候,如果发现这两个string对应的char对应到的index不一样的话,就return false;如果一样且不为零的话,将它map到现在的位置,如果为零的话其实也可以map到现在的位置,两种情况可以合在一起。

这种方法有一点点难想,但是代码写起来比上一种简洁多了。底下存当前位置的时候要+1是因为最开始初始化为0了。时间4ms,99.63%,时间上要快好多,空间9.1M,90%:

class Solution {
public:
    bool isIsomorphic(string s, string t) {
        char s_char[128] = {0};
        char t_char[128] = {0};
        
        for (int i = 0; i < s.length(); i++) {
            if (s_char[s[i]] != t_char[t[i]]) {
                return false;
            }
            else {
                s_char[s[i]] = i + 1;
                t_char[t[i]] = i + 1;
            }
        }
        return true;
    }
};

下面又是另一种方法,就是把原始的string transform成另一种形式,比如把相同的字母都map到同一个数字,最后形成一个list/string,然后比较这两个list/string看是否相等。

class Solution {
    public boolean isIsomorphic(String s, String t) {
        return stringToList(s).equals(stringToList(t));
    }
    private List<Integer> stringToList(String s) {
        List<Integer> list = new ArrayList<>();
        Map<Character, Integer> map = new HashMap<>();
        int count = 0;
        for (char c : s.toCharArray()) {
            if (!map.containsKey(c)) {
                map.put(c, count);
            }
            int index = map.get(c);
            list.add(index);
            count++;
        }
        return list;
    }
}

还看到了别人的解法,用了一个map存s到t的mapping,用一个set存在t里见过的char。遍历的时候只需要判断这个char是否存在在这个map里,如果存在的话判断一下是不是之前的mapping,不存在的话判断一下t对应的char是否已经存在。

class Solution {
    public boolean isIsomorphic(String s, String t) {
        Map<Character, Character> map = new HashMap<>();
        Set<Character> set = new HashSet<>();
        for (int i = 0; i < s.length(); i++) {
            char sc = s.charAt(i);
            char tc = t.charAt(i);

            // if char in s is not in the map but already appeared in t
            if (!map.containsKey(sc) && set.contains(tc)) {
                return false;
            }
            // if char is in s but the mapping is not to t
            if (map.containsKey(sc) && map.get(sc) != tc) {
                return false;
            }
            map.put(sc, tc);
            set.add(tc);
        }
        return true;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值