printvertically Java,LeetCode 1324. Print Words Vertically

@(LeetCode)

问题描述

给定一个字符串 s。按单词出现的先后顺序,以纵向排列的方式返回,结果为一个字符串数组。每一个单词放在单独的一列,如果有需要加上空格,但是末尾不允许出现空格。

栗 1:

输入:s = "HOW ARE YOU"

输出:["HAY","ORO","WEU"]

解释:每个单词纵向排列如下。

"HAY"

"ORO"

"WEU"

栗 2:

输入:s = "TO BE OR NOT TO BE"

输出:["TBONTB","OEROOE"," T"]

解释:每个单词纵向排列如下,且末尾不能有空格。所以 T 后面无空格。

"TBONTB"

"OEROOE"

" T"

栗 3:

输入:s = "CONTEST IS COMING"

输出:["CIC","OSO","N M","T I","E N","S G","T"]

解释:每个单词纵向排列如下,同样 T 后面不能有空格。

"CIC"

"OSO"

"N M"

"T I"

"E N"

"S G"

"T"

注意:

1 <= s.length <= 200。

s 只包含大写字母。

在两个单词之间只有一个空格。

解题思路

看过栗子后,题意应该比较清楚了。将每个单词纵向排列,必要时加空格,且末尾不能有空格。

纵向排列

纵向排列比较好办,类似组建二维数组的方式,只不过是纵向填充。

观察结果,我们可以发现单词中第一个字符对应第 1 行,第二个字符对应第 2 行,以此类推。因此,只需要遍历单词的字符,取到对应的行填入即可。

必要时加空格

若某个单词的长度 < 后面某个单词的长度,需要补加空格。如下所示:

HH 和 AM 后面有比其更长的单词。

s = "HH AM WHO"

"HAW"

"HMH"

" O"

末尾不能有空格

对于某个单词,其后没有比它更长的单词的时候,不需要加空格。

在下例中,当 AB 纵向排列时,其后不需要再加空格,因为它后面没有比它长的单词。

s = "HOW AB C"

"HAC"

"OB"

"W"

解法 1

我最初的想法是,补加空格是按照最长的单词去补,因此只需求出字符串中组最长的单词。在遍历每个单词的时候,计算出需要补的空格数进行填补即可。但是,会产生末尾空格的情况,用 trim 方式再次进行处理。

这种方式虽然能达到效果,但肯定不太好。需要遍历多次,外加额外的去除空格处理。

代码如下:

var printVertically = function(s) {

let i = 0

let maxLen = 0

let len = 0

// 计算单词的最大长度

while (i <= s.length) {

if (i === s.length || s[i] === ' ') {

if (len > maxLen) {

maxLen = len

}

len = 0

} else {

len += 1

}

i += 1

}

// 初始化结果数组

let result = new Array()

let j = 0

while (j < maxLen) {

result.push('')

j += 1

}

let k = 0

let index = -1

while (k <= s.length) {

// 到末尾或者一个单词结束

if (k === s.length || s[k] === ' ') {

// 当前单词长度

let m = index + 1

// 如果比最大单词长度短,则补空格

while (m < maxLen) {

let list = result[m]

list += ' '

result[m] = list

m += 1

}

index = -1

} else {

// 行数

index += 1

// 取出对应的行

let list = result[index]

list += s[k]

result[index] = list

}

k += 1

}

// 去除末尾空格

const trimmedResult = result.map(str => {

return str.trimEnd()

})

return trimmedResult

};

解法 2

我们再来回顾一下什么情况下该加空格?

若某个单词的长度 < 后面某个单词的长度,需要加空格。

所以主要问题在于,如何知道某个单词后面是否有单词比它长?

稍微想一想,如果从头开始遍历,是无法得知的。但是,换种思路,倒着遍历,却是可以的。

因此,我们只需要记录从后往前遍历时最大单词的长度 maxLen,然后与当前单词长度 curLen 比较。如果 curLen < maxLen,则需加空格,反之不需要。

这样一次遍历就可以解决问题,也不会有末尾空格的困扰。因为只在该加的地方才加了空格。

注意:由于是反向遍历,在取单词时,需要注意字符串相加的顺序。

// 反向遍历, 97.77%

var printVertically2 = function(s) {

let result = new Array()

// 单词

let word = ''

// 是否是完整单词

let wordFlag = false

// 记录已遍历单词最大长度

let preLen = 0

// 从末尾遍历

let i = s.length - 1

while (i >= 0) {

if (s[i] !== ' ') {

// 注意顺序

word = s[i] + word

// 一个完整单词

if (i === 0) {

wordFlag = true

}

} else {

// 一个完整的单词

wordFlag = true

}

if (wordFlag) {

// 遍历单词

let j = 0

while (j < word.length) {

let list = ''

// 取数组元素,不存在

if (result.length <= j) {

result.push(list)

} else {

list = result[j]

}

// 注意顺序

list = word[j] + list

result[j] = list

j += 1

}

// 如果字符串长度小于前面最大字符串长度,需要填补空格

if (word.length < preLen) {

let k = 0

while (k < preLen - word.length) {

const m = k + word.length

let list = ''

// 不存在

if (result.length <= m) {

result.push(list)

} else {

list = result[m]

}

// 注意顺序

list = ' ' + list

result[m] = list

k += 1

}

}

// 更新最大长度

if (word.length > preLen) {

preLen = word.length

}

wordFlag = false

word = ''

}

i -= 1

}

return result

}

解法 3

思路

以上两种解法都是以一个单词纵向排列的切入点去思考,即按列生成。其实我们也可以考虑按行生成。

通过观察,我们可以发现如下规律:

第一行:第一个单词的第一个字符 + 第二个单词的第一个字符 + ... + 第 m 个单词的第一个字符

第二行:第一个单词的第二个字符 + 第二个单词的第二个字符 + ... + 第 m 个单词的第一个字符

...

第 n 行:第一个单词的第 n 个字符(如果没有,则为空格) + 第二个单词的第 n 个字符 + ... + 第 m 个单词的第一个字符

但这样会产生末尾空格的问题,不过也好解决。只需取子串 [0, index],其中 index 为长度 >= n 的最后一个单词的索引,即是第几个单词。

栗子

比如 s = "WHAT DO YOU DO",下面列出排列过程。

第一行,分别取每个单词的第一个字符。"WAYD"

第二行,分别取每个单词的第二个字符。"HOOO"

第三行,初始结果为 "A U "。由于 DO/DO 的长度小于 3,所以补空格。但这样 U 后面会出现末尾空格,而长度 >= 3 的单词索引为 2,那么取其子串 [0,2],结果为 "A U"。

第四行,初始结果为 "T "。由于 ARE/YOU/DO 的长度均小于 4,所以补空格。同样的出现了末尾空格,而长度 >= 4 的单词索引为 0,所以取其子串 [0, 0],结果为 "T"。

因此,最终结果为:

"WDYD"

"HOOO"

"A U"

"T"

代码如下:

// 横向填充, 58.36%

var printVertically3 = function(s) {

if (s && s.length > 0) {

// 分隔单词

const wordList = s.split(' ')

if (wordList && wordList.length > 0) {

let index = 0

let maxLen = 1

let result = new Array()

// 逐步生成行,最大行数为单词的最大长度

while (index < maxLen) {

let str = ""

let i = 0

let lastIndex = 0

while (i < wordList.length) {

const word = wordList[i]

// 同时计算最大长度

if (word.length > maxLen) {

maxLen = word.length

}

if (index < word.length) {

// 记录单词索引

lastIndex = i

str += word[index]

} else {

// 补空格

str += " "

}

i += 1

}

index += 1

// 取子串

const substr = str.slice(0, lastIndex + 1)

result.push(substr)

}

return result

}

}

return []

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值