力扣每日一题0811-1417. 重新格式化字符串

224 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情

给你一个混合了数字和字母的字符串 s,其中的字母均为小写英文字母。

请你将该字符串重新格式化,使得任意两个相邻字符的类型都不同。也就是说,字母后面应该跟着数字,而数字后面应该跟着字母。

请你返回 重新格式化后 的字符串;如果无法按要求重新格式化,则返回一个 空字符串

示例 1:

输入:s = "a0b1c2"
输出:"0a1b2c"
解释:"0a1b2c" 中任意两个相邻字符的类型都不同。 "a0b1c2", "0a1b2c", "0c2a1b" 也是满足题目要求的答案。

示例 2:

输入:s = "leetcode"
输出:""
解释:"leetcode" 中只有字母,所以无法满足重新格式化的条件。

示例 3:

输入:s = "1229857369"
输出:""
解释:"1229857369" 中只有数字,所以无法满足重新格式化的条件。

双指针

题目给定字符串 ss,我们记 sum_digit\textit{sum\_digit} 为字符串中数字的个数,sum_alpha\textit{sum\_alpha} 为字符串中字母的个数。那么能按照题目要求格式化字符串的充要条件为:

sumdigitsumalpha1∣sum_digit−sum_alpha∣≤1

那么当给定字符串 ss 满足上述条件时,我们把数字和字母中个数多的放在偶数位上(字符串下标从 00 开始),个数少的放在奇数位上,此时可以构造出满足题目条件的字符串。那么我们用 iijj 来分别表示个数多的和个数少的字符放置的下标,初始为 i=0,j=1i = 0, j = 1,然后从左到右移动 ii,当 s[i]s[i] 为个数少的字符类型时,那么向右移动 jj 找到往后的第一个 s[j]s[j] 为个数多的字符类型,然后交换两个字符即可,不断重复该过程直至 ii 移动到字符串结尾即可。

var reformat = function(s) {
    let sumDigit = 0;
    for (let i = 0; i < s.length; i++) {
        const c = s[i];
        if (isDigit(c)) {
            sumDigit++;
        }
    }
    let sumAlpha = s.length - sumDigit;
    if (Math.abs(sumDigit - sumAlpha) > 1) {
        return "";
    }
    let flag = sumDigit > sumAlpha;
    const arr = [...s];
    for (let i = 0, j = 1; i < s.length; i += 2) {
        if (isDigit(arr[i]) !== flag) {
            while (isDigit(arr[j]) !== flag) {
                j += 2;
            }
            [arr[i], arr[j]] = [arr[j], arr[i]];
        }
    }
    return arr.join('');
}

const isDigit = (ch) => {
    return parseFloat(ch).toString() === "NaN" ? false : true;
}