题:https://leetcode.com/problems/di-string-match/description/
题目
Given a string S that only contains “I” (increase) or “D” (decrease), let N = S.length.
Return any permutation A of [0, 1, …, N] such that for all i = 0, …, N-1:
If S[i] == “I”, then A[i] < A[i+1]
If S[i] == “D”, then A[i] > A[i+1]
Example 1:
Input: "IDID"
Output: [0,4,1,3,2]
Example 2:
Input: "III"
Output: [0,1,2,3]
Example 3:
Input: "DDI"
Output: [3,2,0,1]
Note:
- 1 <= S.length <= 10000
- S only contains characters “I” or “D”.
题目大意
给定一个字符串 S,长度为 n,构造一个长度为 n+1 的数组,数组元素为 0,1,2 …… n,且数组满足 下面的规则。
If S[i] == "I", then A[i] < A[i+1]
If S[i] == "D", then A[i] > A[i+1]
思路
方法一 取局部最小
找出 数组中的 局部最小,即 A[i-1] < A[i] > A[i+1],对于边界 A[0]<A[1] , A[n]<A[n-1]。对于这些局部最小A[i],从小到大分配 数组的元素(0,1,2,……,n)。
当确定一个局部最小后, 其左或右 位置的另一边 若是 小于 其他元素。那么左或右 位置也可以视为局部 最小。
class Solution {
public int[] diStringMatch(String S) {
int Slen = S.length();
boolean [][] dp = new boolean[Slen+1][2];
dp[0][0] = true;
dp[Slen][1] = true;
for(int i = 0 ;i<Slen;i++){
if(S.charAt(i) == 'I')
dp[i][1] = true;
else
dp[i+1][0] = true;
}
int Cnt = 0 ;
int[] res = new int[Slen+1];
Queue<Integer> queue = new ArrayDeque<>();
for(int i = 0 ;i <= Slen;i++){
if(dp[i][0] == true && dp[i][1] == true){
res[i] = Cnt++;
queue.add(i);
}
}
while(!queue.isEmpty()){
int i = queue.poll();
int l = i -1;
int r = i+1;
if(l>=0 && dp[l][1]==false){
dp[l][1] = true;
if(dp[l][0] == true){
res[l] = Cnt++;
queue.add(l);
}
}
if(r<=Slen && dp[r][0]==false){
dp[r][0] = true;
if(dp[r][1] == true){
res[r] = Cnt++;
queue.add(r);
}
}
}
return res;
}
}
方法二 更新边界
S[0]+S[1:],确定 A[i],i=0,1,2,……,n;
若S[0]<S[1],A[0] 可设为0, S[1:] 可确定出一个数组,数组元素为 1, 2, ……,n。
若S[0]>S[1],A[0] 可设为n, S[1:] 可确定出一个数组,数组元素为0, 1, 2, ……,n-1。
class Solution {
public int[] diStringMatch(String S) {
int Slen = S.length();
int li = 0,ri = Slen;
int[] res = new int[Slen+1];
for(int i = 0 ; i < Slen;i++){
if(S.charAt(i) == 'I')
res[i] = li++;
else
res[i] = ri--;
}
res[Slen] = li;
return res;
}
}