leetcode
leetcode 851 ~ 900
增减字符串匹配

增减字符串匹配

难度:

标签:

题目描述

代码结果

运行时间: 19 ms, 内存: 16.7 MB


/*
 * 思路:我们可以使用双指针的方法从两端向中间填充数字。
 * 我们初始化一个低指针low为0和一个高指针high为n。
 * 我们遍历字符串s,如果s[i] == 'I',则将low的值赋给perm[i],然后增加low。
 * 如果s[i] == 'D',则将high的值赋给perm[i],然后减少high。
 * 在最后一个位置,将low或high的值赋给perm[n]。
 * 使用Java Stream API实现上述逻辑。
 */

import java.util.stream.IntStream;

public class Solution {
    public int[] diStringMatch(String s) {
        int n = s.length();
        int[] low = {0};
        int[] high = {n};
        int[] perm = IntStream.range(0, n)
                               .map(i -> s.charAt(i) == 'I' ? low[0]++ : high[0]--)
                               .toArray();
        perm = IntStream.concat(IntStream.of(perm), IntStream.of(low[0])).toArray();
        return perm;
    }
}

解释

方法:

该题解采用了两个指针策略,up 和 down。up 从0开始递增,代表在排列中下一个最小的数字;down 从n开始递减,代表在排列中下一个最大的数字。遍历给定的字符串s,根据每个字符是'I'(递增)还是'D'(递减),从up或down取值填充结果数组。最后一个位置用剩余的up或down填充,保证所有数字都被使用。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在字符串s中每个字符处理时选择更新up或down而不是同时更新两个指针?
算法设计的初衷是为了根据字符串s中的'I'和'D'来构建一个满足条件的排列。每次选择更新up或down是为了能够清晰地表示递增或递减的关系。若同时更新两个指针,则会失去这种一致的递增或递减的映射关系,导致无法直接通过'I'或'D'来决定具体的数值。此外,这种单一指针更新策略简化了逻辑,并确保了数组中的每个数都是唯一且适当的。
🦆
在字符串s的处理完毕后,为何剩余的up或down的值可以直接用于填充数组的最后一个位置?这样做有何保证?
在字符串s处理完毕后,下一个待填充的数组位置是最后一个元素。这时,up指针和down指针会恰好指向同一个数值。这是因为up始终指向未被使用的最小值,而down指向未被使用的最大值,当遍历完字符串s后,剩下的唯一未被使用的数恰好是这两个指针相遇的地方。因此,可以保证剩余的up或down的值可以直接用于填充数组的最后一个位置,同时确保所有数字从0到n都被使用一次,无遗漏。
🦆
如果给定字符串s全是'I'或全是'D',这种情况下算法的表现如何?会不会有特殊的处理方式或优化?
如果字符串s全是'I',则表示数组需要完全递增,此时算法会从0开始依次递增至n。如果字符串s全是'D',则表示数组需要完全递减,此时算法会从n开始依次递减至0。这种情况下算法的基本逻辑不变,且没有必要进行特殊的处理或优化,因为该算法已经以最简洁的方式处理了这些极端情况。这也体现了算法的通用性和效率。
🦆
代码中对于字符'I'和'D'的处理逻辑为何选择将较小的数赋给'I',较大的数赋给'D'?这样的逻辑有何特定的优势?
这样的设计是为了直接映射字符'I'和'D'的字面意义——'I'代表递增,'D'代表递减。通过将较小的数赋给'I',可以确保数字序列在遇到'I'时呈现递增趋势;相反,将较大的数赋给'D'可以确保数字序列在遇到'D'时呈现递减趋势。这种处理逻辑简化了算法的实现,并且直观上与问题描述保持一致,易于理解和验证。此外,这种方法也避免了额外的计算或调整,提高了算法的效率。

相关问题