100131. Make Three Strings Equal

给你三个字符串 s1、s2 和 s3。 你可以根据需要对这三个字符串执行以下操作 任意次数 。

在每次操作中,你可以选择其中一个长度至少为 2 的字符串 并删除其 最右位置上 的字符。

如果存在某种方法能够使这三个字符串相等,请返回使它们相等所需的 最小 操作次数;否则,返回 -1。

测试样例:

输入:s1 = "abc",s2 = "abb",s3 = "ab"

输出:2

解释:
对 s1 和 s2 进行一次操作后,可以得到三个相等的字符串。
可以证明,不可能用少于两次操作使它们相等。

解答:最长前缀相同的字符串。如果最长前缀为0,需要返回-1.

class Solution {
    public int findMinimumOperations(String s1, String s2, String s3) {
        String t = common(s1, s2);
        t = common(t, s3);
        return t.length() == 0 ? -1 : (s1.length() - t.length() + s2.length() - t.length() + s3.length() - t.length());
    }

    private String common(String s1, String s2) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < Math.min(s1.length(), s2.length()); ++i) {
            if (s1.charAt(i) == s2.charAt(i)) {
                sb.append(s1.charAt(i));
            } else {
                break;
            }
        }
        return sb.toString();
    }
}

100122. Separate Black and White Balls

桌子上有 n 个球,每个球的颜色不是黑色,就是白色。

给你一个长度为 n 、下标从 0 开始的二进制字符串 s,其中 1 和 0 分别代表黑色和白色的球。

在每一步中,你可以选择两个相邻的球并交换它们。

返回「将所有黑色球都移到右侧,所有白色球都移到左侧所需的 最小步数」。

测试样例:

输入:s = "101"

输出:1

解释:
我们可以按以下方式将所有黑色球移到右侧:

  • 交换 s[0] 和 s[1],s = "011"。

最开始,1 没有都在右侧,需要至少 1 步将其移到右侧。

解答:将所有白球移到左边,记录最左的位置,然后移动白球累和。注意返回的是long,不要用int爆范围了。

class Solution {
    public long minimumSteps(String s) {
        int white = 0;
        long res = 0;
        for (int i = 0; i < s.length(); ++i) {
            if (s.charAt(i) == '0') {
                res += (i - white);
                ++white;
            }
        }
        return res;
    }
}

100119. Maximum Xor Product

给你三个整数 a ,b 和 n ,请你返回 (a XOR x) * (b XOR x) 的 最大值 且 x 需要满足 0 <= x < 2n。

由于答案可能会很大,返回它对 10^9 + 7 取余 后的结果。

注意,XOR 是按位异或操作。

测试样例:

输入:a = 12, b = 5, n = 4

输出:98

解释:
当 x = 2 时,(a XOR x) = 14 且 (b XOR x) = 7 。所以,(a XOR x) (b XOR x) = 98 。
98 是所有满足 0 <= x < 2n 中 (a XOR x)
(b XOR x) 的最大值。

解答:这周最恶心的一道题目了。如果a和b在小于n的位数,某一位相同,那么可以通过异或操作同时变成1.问题在于如果不相同怎么办。如果反转(a - c) (b + c) = a b + c * (a - b + c)。那么第一位不同的位数,可以确定之后是否反转。

class Solution {
    private static final int mod = 1_000_000_007;

    public int maximumXorProduct(long a, long b, int n) {
        boolean isA = true, isFirst = true;
        for (int i = 49; i >= 0; --i) {
            if (i >= n) {
                if (isMark(a, i) + isMark(b, i) == 1) {
                    if (isFirst && isMark(b, i) == 1) {
                        isA = false;
                    }
                    isFirst = false;
                }
            } else {
                if (isMark(a, i) + isMark(b, i) == 0) {
                    a += (1L << i);
                    b += (1L << i);
                } else if (isMark(a, i) + isMark(b, i) == 1) {
                    if (isFirst) {
                        if (isMark(a, i) == 0) {
                            a += (1L << i);
                            b -= (1L << i);
                        }
                    } else {
                        if (isA && isMark(a, i) == 1) {
                            a -= (1L << i);
                            b += (1L << i);
                        } else if (!isA && isMark(a, i) == 0) {
                            a += (1L << i);
                            b -= (1L << i);
                        }
                    }
                    isFirst = false;
                }
            }
        }
        return (int)((a % mod) * (b % mod) % mod);
    }

    private int isMark(long num, int offset) {
        int tmp = (int) ((num >> offset) & 1);
        return tmp;
    }
}

100110. Find Building Where Alice and Bob Can Meet

给你一个下标从 0 开始的正整数数组 heights ,其中 heights[i] 表示第 i 栋建筑的高度。

如果一个人在建筑 i ,且存在 i < j 的建筑 j 满足 heights[i] < heights[j] ,那么这个人可以移动到建筑 j 。

给你另外一个数组 queries ,其中 queries[i] = [ai, bi] 。第 i 个查询中,Alice 在建筑 ai ,Bob 在建筑 bi 。

请你能返回一个数组 ans ,其中 ans[i] 是第 i 个查询中,Alice 和 Bob 可以相遇的 最左边的建筑 。如果对于查询 i ,Alice 和 Bob 不能相遇,令 ans[i] 为 -1 。

测试样例

输入:heights = [6,4,8,5,2,7], queries = [[0,1],[0,3],[2,4],[3,4],[2,2]]

输出:[2,5,-1,5,2]

解释:
第一个查询中,Alice 和 Bob 可以移动到建筑 2 ,因为 heights[0] < heights[2] 且 heights[1] < heights[2] 。
第二个查询中,Alice 和 Bob 可以移动到建筑 5 ,因为 heights[0] < heights[5] 且 heights[3] < heights[5] 。
第三个查询中,Alice 无法与 Bob 相遇,因为 Alice 不能移动到任何其他建筑。
第四个查询中,Alice 和 Bob 可以移动到建筑 5 ,因为 heights[3] < heights[5] 且 heights[4] < heights[5] 。
第五个查询中,Alice 和 Bob 已经在同一栋建筑中。
对于 ans[i] != -1 ,ans[i] 是 Alice 和 Bob 可以相遇的建筑中最左边建筑的下标。
对于 ans[i] == -1 ,不存在 Alice 和 Bob 可以相遇的建筑。

解答:其实感觉这题比第三题简单多了。这道题目利用单调栈和排序就能搞定了。我们将queries按照Math.max(queries[i][0], queries[i][1])降序摆列。然后开始遍历queries,我们利用单调栈维护右侧数组降序排列,每次利用折半搜索就能寻找到最左的位置。

class Solution {
    private class Stack {
        List<Integer> stack;
        int pos;

        public Stack() {
            stack = new ArrayList<>();
            pos = -1;
        }

        public int peek() {
            return stack.get(pos);
        }

        public void pop() {
            --pos;
        }

        public void push(int x) {
            ++pos;
            if (pos == stack.size()) {
                stack.add(x);
            } else {
                stack.set(pos, x);
            }
        }

        public boolean isEmpty() {
            return pos < 0;
        }
    }

    public int[] leftmostBuildingQueries(int[] heights, int[][] queries) {
        for (int i = 0; i < queries.length; ++i) {
            int min = Math.min(queries[i][0], queries[i][1]);
            int max = Math.max(queries[i][0], queries[i][1]);
            queries[i][0] = min;
            queries[i][1] = max;
        }
        Integer[] sort = new Integer[queries.length];
        for (int i = 0; i < sort.length; ++i) {
            sort[i] = i;
        }
        Arrays.sort(sort, (a, b) -> (queries[b][1] - queries[a][1]));
        int pos = heights.length - 1, memPos = -1;
        Stack stack = new Stack();
        int[] res = new int[queries.length];
        for (int i : sort) {
            while (pos >= queries[i][1]) {
                int h = heights[pos];
                while (!stack.isEmpty() && heights[stack.peek()] <= h) {
                    stack.pop();
                }
                stack.push(pos);
                --pos;
            }
            if (heights[queries[i][0]] < heights[queries[i][1]] || queries[i][0] == queries[i][1]) {
                res[i] = queries[i][1];
            } else {
                int st = 0, ed = stack.pos;
                while (st < ed) {
                    int mid = (st + ed + 1) / 2;
                    if (heights[stack.stack.get(mid)] > heights[queries[i][0]]) {
                        st = mid;
                    } else {
                        ed = mid - 1;
                    }
                }
                if (heights[stack.stack.get(st)] > heights[queries[i][0]]) {
                    res[i] = stack.stack.get(st);
                } else {
                    res[i] = -1;
                }
            }
        }
        return res;
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *