Jerry's Blog

Recording what I learned everyday

View on GitHub


13 October 2019

LeetCode(36) -- 821, 824, 830, 832, 836

by Jerry Zhang

P821. Shortest Distance to a Character (Easy)

给一个字符串和一个字母,找出这个字符串每个字母,距离这个字母最短的距离。

Input: S = "loveleetcode", C = 'e'
Output: [3, 2, 1, 0, 1, 0, 0, 1, 2, 2, 1, 0]

我的思路

肯定要把这个字符串中所有这个字母的坐标找出来,否则我走着走着并不知道前方还有一个,距离肯定算不对。 然后就控制一下索引,使距离不要超过中点。

我的代码

public class E_821_Shortest_Distance_to_a_Character {
    public int[] shortestToChar(String S, char C) {
        LinkedList indexes = new LinkedList();
        char[] chars = S.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == C) {
                indexes.addAtTail(i);
            }
        }
        int[] ans = new int[chars.length];
        int first = indexes.getFirst();
        int i = 0;
        while (i < first) {
            ans[i] = first - i;
            i++;
        }

        while (indexes.getSecond() != -1) {
            first = indexes.getFirst();
            int second = indexes.getSecond();
            int mid = first + (second - first) / 2;
            while (i <= mid) {
                ans[i] = i - first;
                i++;
            }
            while (i < second) {
                ans[i] = second - i;
                i++;
            }
            indexes.removeFirst();
        }
        first = indexes.getFirst();
        while (i < chars.length) {
            ans[i] = i - first;
            i++;
        }
        return ans;
    }

    static class LinkedListNode {
        int index;
        LinkedListNode next;

        public LinkedListNode() {
        }

        LinkedListNode(int index, LinkedListNode next) {
            this.index = index;
            this.next = next;
        }
    }

    static class LinkedList {
        LinkedListNode head;
        LinkedListNode tail;
        int size;

        void addAtHead(int index) {
            head = new LinkedListNode(index, head);
            if (size == 0) {
                tail = head;
            }
            size++;
        }

        void removeFirst() {
            if (head != null) {
                head = head.next;
                size--;
            }
        }

        void addAtTail(int index) {
            if (size == 0) {
                addAtHead(index);
            } else {
                tail.next = new LinkedListNode(index, null);
                tail = tail.next;
                size++;
            }
        }

        int getFirst() {
           if (size == 0) {
               return -1;
           }
           return head.index;
        }

        int getSecond() {
            if (size < 2) {
                return -1;
            }
            return head.next.index;
        }

        int getLast() {
            if (size == 0) {
                return -1;
            }
            return tail.index;
        }

        public int size() {
            return size;
        }
    }
}

98% 自己写了一个LinkedList,所以代码长得有点吓人…

最优解

class Solution {
    public int[] shortestToChar(String s, char c) {
        char[] arr = s.toCharArray();
        int n = arr.length;

        int[] ans = new int[n];
        int i=0, dist = 0;
        while(arr[i] != c) ans[i++] = Integer.MAX_VALUE;

        for(; i<n; ++i) {
            if(arr[i] == c) {
                ans[i] = 0;
                dist = 1;
                int j = i-1;
                while(j >= 0 && ans[j] > dist) ans[j--] = dist++;
                dist = 1;
            } else ans[i] = dist++;
        }

        return ans;
    }
}

这个算法太巧妙了!不知道后一个目标值在哪里没关系,距离先暂时累加着,直到遇到下一个目标值,再回头,把距离改回来。第一轮的时候,因为没有初始值,所以先把所有的数都设置成最大整数,这样前面的所有数肯定是大于distance的,也就是说要回头一直走到数组的初始。

P824. Goat Latin (Easy)

给一个字符串写着一句话,每个单词只有大小写字母。如果这个单词以元音字母开头,则在单词结尾加上“ma”,如果以辅音字母开头,则把每一个字母挪到最后,再加上”ma”。同时该单词在句子中,是第几个单词就加几个“a”。

Input: "I speak Goat Latin"
Output: "Imaa peaksmaaa oatGmaaaa atinLmaaaaa"

我的思路

并不难,根据规则实现即可。

我的代码

public class E_824_GoatLatin {
    public String toGoatLatin(String S) {
        String[] words = S.split(" ");
        StringBuilder ans = new StringBuilder();
        for (int i = 0; i < words.length; i++) {
            char first = words[i].charAt(0);
            if (first == 'a' || first == 'e' || first == 'i' || first == 'o' || first == 'u' ||
                first == 'A' || first == 'E' || first == 'I' || first == 'O' || first == 'U') {
                ans.append(words[i]);
            } else {
                ans.append(words[i].substring(1)).append(words[i].charAt(0));
            }
            ans.append("ma");
            for (int j = 0; j < i + 1; j++) {
                ans.append('a');
            }
            ans.append(" ");
        }
        return ans.toString().trim();
    }
}

94%

最优解

class Solution {
    public String toGoatLatin(String S) {
        StringBuffer sbf = new StringBuffer();

        if(S != null && S.length() > 0) {
            boolean start = true;
            String postFix = "";
            int wordCount = 1;
            for(int i = 0; i < S.length(); i++) {
                char ch = S.charAt(i);
                if(ch == ' ') {
                    if(!start) {
                        start = true;
                        wordCount++;
                        sbf.append(postFix);
                        sbf.append('m');
                        for(int j=0; j < wordCount; j++) {
                            sbf.append('a');
                        }
                    }
                    sbf.append(ch);
                } else {
                    if(start) {
                        char lch = Character.toLowerCase(ch);
                        if(lch == 'a' || lch == 'e' || lch == 'i' || lch == 'o' || lch == 'u') {
                            sbf.append(ch);
                            postFix = "";
                        } else {
                            postFix = Character.toString(ch);
                        }
                        start = false;
                    } else sbf.append(ch);
                }
            }
            sbf.append(postFix);
            sbf.append('m');
            for(int j=0; j<wordCount+1; j++) {
                sbf.append('a');
            }
        }
        return sbf.toString();
    }
}

没啥值得学习的。代码看着比我的乱。

P830. Positions of Large Groups (Easy)

字符串,连续的相同的字母分为一组。求长度大于3的起始坐标和终止坐标。

我的思路

按要求实现即可。

我的代码

public class E_830_PositionsOfLargeGroups {
    public List<List<Integer>> largeGroupPositions(String S) {
        List<List<Integer>> list = new ArrayList<>();
        char[] chars = S.toCharArray();
        int first = 0;
        char curr = chars[0];
        int count = 0;
        for (int i = 0; i < chars.length; i++) {
            while (i < chars.length && chars[i] == curr) {
                count++;
                i++;
            }
            if (count >= 3) {
                List<Integer> index = new ArrayList<>();
                index.add(first);
                index.add(i - 1);
                list.add(index);
            }
            if (i < chars.length) {
                count = 1;
                first = i;
                curr = chars[i];
            }
        }
        return list;
    }
}

100% 测试case给了一个‘a’,出了两次bug

最优解

class Solution {
    public List<List<Integer>> largeGroupPositions(String S) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> temp = new ArrayList<>();
        if(S.length() < 3) {
            return res;
        }
        char[] chars = S.toCharArray();
        int counter = 1;

        for(int i = 1; i <= chars.length; i++) {
            if(i == chars.length) {
                if(counter >= 3){
                    temp.add(i - counter);
                    temp.add(i - 1);
                    res.add(temp);
                }
                break;
            }
            if(chars[i] == chars[i - 1])
                counter++;
            else {
                if(counter >= 3) {
                    temp.add(i - counter);
                    temp.add(i - 1);
                    res.add(temp);
                    temp = new ArrayList<>();
                }
                counter = 1;
            }
        }

        return res;
    }
}

差不多。

P832. Flipping an Image (Easy)

二维数组,每一行先反转,再把1,0互换。

我的思路

换要求实现即可。

我的代码

class Solution {
    public int[][] flipAndInvertImage(int[][] A) {
        for (int i = 0; i < A.length; i++) {
            int length = A[i].length;
            for (int j = 0; j < length / 2; j++) {
                int temp = A[i][j];
                A[i][j] = A[i][length - j - 1];
                A[i][length - j - 1] = temp;
            }
            for (int j = 0; j < length; j++) {
                if (A[i][j] == 0) {
                    A[i][j] = 1;
                } else {
                    A[i][j] = 0;
                }
            }
        }
        return A;
    }
}

36%

最优解

class Solution {
    public int[][] flipAndInvertImage(int[][] A) {
        for (int i = 0; i< A.length; i++) {
            int[] curRow = A[i];
            int len = curRow.length;
            for (int j = 0; j < (len+1)/2; j++) {
                int k = len-1-j;
                int temp = curRow[j];
                curRow[j] = curRow[k];
                curRow[k] = temp;
                curRow[j] ^= 1;
                if (j != k)
                    curRow[k] ^= 1;
            }
        }
        return A;
    }
}

跟“1”做“异或”实现反转

答案

class Solution {
    public int[][] flipAndInvertImage(int[][] A) {
        int C = A[0].length;
        for (int[] row: A)
            for (int i = 0; i < (C + 1) / 2; ++i) {
                int tmp = row[i] ^ 1;
                row[i] = row[C - 1 - i] ^ 1;
                row[C - 1 - i] = tmp;
            }

        return A;
    }
}

P836. Rectangle Overlap (Easy)

[x1, y1, x2, y2]表示一个长方形,x1,y1是左下角的坐标,x2,y2是右上角的坐标。 给两个长方形,问是否重叠。只有边或点接触不算,必须真的有重叠的面积。

我的思路

第一个长方形的x1要小于第二个长方形的x2,并且第一个长方形的x2要大于第二个长方形的x1。纵坐标也类似。

我的代码

class Solution {
    public boolean isRectangleOverlap(int[] rec1, int[] rec2) {
        boolean horizontalOverlap = false;
        boolean verticalOverlap = false;
        if (rec1[0] < rec2[2] && rec1[2] > rec2[0]) {
            horizontalOverlap = true;
        }
        if (rec1[1] < rec2[3] && rec1[3] > rec2[1]) {
            verticalOverlap = true;
        }
        return horizontalOverlap && verticalOverlap;
    }
}

100% 关于重叠的问题,基本都是这个思路。

最优解

class Solution {
    public boolean isRectangleOverlap(int[] rec1, int[] rec2) {
        return !(rec1[2] <= rec2[0] ||   // left
                 rec1[3] <= rec2[1] ||   // bottom
                 rec1[0] >= rec2[2] ||   // right
                 rec1[1] >= rec2[3]);    // top
    }
}

其实就是我上面那四个条件反着说。

tags: LeetCode