N 字形变换

我打螺丝回来了,每日算法更新继续!!!!

来,题目展示。

将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:

css 复制代码
P   A   H   N
A P L S I I G
Y   I   R

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"。

请你实现这个将字符串进行指定行数变换的函数:

c 复制代码
string convert(string s, int numRows);

示例 1:

ini 复制代码
输入: s = "PAYPALISHIRING", numRows = 3
输出: "PAHNAPLSIIGYIR"

示例 2:

css 复制代码
输入: s = "PAYPALISHIRING", numRows = 4
输出: "PINALSIGYAHRPI"
解释:
P     I    N
A   L S  I G
Y A   H R
P     I

示例 3:

ini 复制代码
输入: s = "A", numRows = 1
输出: "A"

提示:

  • 1 <= s.length <= 1000
  • s 由英文字母(小写和大写)、',' 和 '.' 组成
  • 1 <= numRows <= 1000

第一次解题

js 复制代码
/**
 * @param {string} s
 * @param {number} numRows
 * @return {string}
 */
const convert = function (s, numRows) {
    // 如果字符串长度小于等于行数,或者行数为1,直接返回原字符串
    if (s.length <= numRows || numRows === 1) {
        return s;
    }

    // 创建一个二维数组,表示 Z 字形排列
    const zArr = Array.from({ length: numRows }, () => []);

    // 初始化当前字符的插入行和插入方向
    let index = 0;
    let direction = 1;

    // 遍历输入字符串
    for (let i = 0; i < s.length; i++) {
        // 将当前字符插入到对应行
        zArr[index].push(s[i]);

        // 判断是否到达 Z 字形的上端或下端,更新插入方向
        if (index === 0) {
            direction = 1; // 如果在第一行,变换为向下方向
        } else if (index === numRows - 1) {
            direction = -1; // 如果在最后一行,变换为向上方向
        }

        // 更新当前字符的插入行
        index += direction;
    }

    // 将二维数组展平并拼接成最终结果的字符串
    return zArr.flat().join('');
};

解题思路

首先判断输入的参数,如果s小于numRows或者numRows是1的话直接返回这个字符串就可以了,如果不满足这两个条件之一的话那么继续,先创建一个二维数组来暂存z字形排列的字符串,来看核心 就是index和direction,当index等于0的时候说明当前插入的在第一个数组,那么此时每个字符就从一个数组到最后一个数组依次插入就好了,当到达最后一个数组也就 numRows-1 的时候,插入顺序就是从倒数第二个数组到第二个数组这样的顺序插入,等这么插插插完之后,就是数组扁平化最后合成字符串返回就完事了。

时间复杂度:

  1. 数组初始化: Array.from({ length: numRows }, () => []); 这一部分的时间复杂度是 O(numRows)。
  2. 遍历字符串: for (let i = 0; i < s.length; i++) 这一部分的时间复杂度是 O(s.length),其中 s 是输入字符串的长度。
  3. 展平数组和拼接字符串: zArr.flat().join('') 这一部分的时间复杂度主要取决于展平数组和拼接字符串的操作,总体来说是 O(s.length)。

因此,整个代码的时间复杂度是 O(s.length)。

空间复杂度:

  1. 二维数组的空间: Array.from({ length: numRows }, () => []); 创建了一个 numRows x k 的二维数组,其中 k 是字符串 s 的平均长度。因此,空间复杂度是 O(numRows * k)。
  2. 其他辅助变量: 除了二维数组之外,还有几个辅助变量(index 和 direction),这些变量占用常量级别的空间。因此,忽略不计。

综上所述,整个代码的空间复杂度是 O(numRows * k)。

第二种解法

js 复制代码
const convert = function (s, numRows) {
    // 如果字符串长度小于等于行数,或者行数为1,直接返回原字符串
    if (s.length <= numRows || numRows === 1) {
        return s;
    }
    
    // 创建一个数组,表示 Z 字形排列的每一行
    const rows = new Array(numRows).fill('');

    // 计算 Z 字形排列中每个循环的长度
    const n = 2 * numRows - 2;

    // 遍历输入字符串
    for (let i = 0; i < s.length; i++) {
        // 计算当前字符在 Z 字形排列中的位置
        const x = i % n;

        // 根据当前位置,将字符添加到相应的行
        rows[Math.min(x, n - x)] += s[i];
    }

    // 将每一行的字符拼接成最终结果的字符串
    return rows.join("");
};

这种解法的是就是找z字形排列的规律,我画个图大家看看

把这个排列拆解成一个一个的v,每一个v的字符数量是numRows + numRows - 2也就是2numRows-2,然后在看看每一个规律,前四个对应着0到3,也就是 i % (2numRows-2), 下来两个分别是2, 1也就是 2numRows-2 - i % (2numRows-2)

这种解法其实我第一次想的就是找规律,但是一直没有找到这个后面的 2numRows-2 - i % (2numRows-2)这个计算的规律,看了别人写的才想出来,还得是广大的网友。

时间复杂度:

  • 字符串遍历: for (let i = 0; i < s.length; i++) 这一部分的时间复杂度是 O(s.length),其中 s 是输入字符串的长度。

整体上,时间复杂度是 O(s.length)。

空间复杂度:

  • 数组初始化: const rows = new Array(numRows).fill(''); 创建了一个长度为 numRows 的数组,这个操作的空间复杂度是 O(numRows)。
  • 其他辅助变量: 除了数组之外,只使用了常量级别的辅助变量(如 n、x、i),因此在空间复杂度的分析中可以忽略。

整体上,空间复杂度是 O(numRows)。

相关推荐
lzhdim35 分钟前
AI的分类
人工智能·算法·机器学习·分类·数据挖掘
程序员海军2 小时前
用了两年多 GPT,我最近开始换模型了,还折腾了个求职避坑 Agent
前端·人工智能·后端
zttbee3 小时前
echarts图表tooltip色块失效
前端·javascript·echarts
凤凰院凶涛QAQ3 小时前
《Java版数据结构 & 集合类剖析》Map & Set & 反射:“从哈希碰撞到红黑树转换,反射帮你扒开 HashMap 的桶数组看个究竟”
java·数据结构·算法
excel4 小时前
IndexNow:让搜索引擎更快发现网站更新的主动通知协议
前端·后端·架构
子兮曰5 小时前
CSS 复现 23 种设计风格:从拟物到液态玻璃的成本阶梯与兜底写法【实战】
前端·css·视觉设计
虚无境5 小时前
如何用AI帮我写出实用的插件
前端·javascript·ai编程
w_zero_one5 小时前
算法--模拟
java·数据结构·算法
柳杉6 小时前
从数字化到数智化:3D 可视化大屏的下一个五年
前端·ai编程·数据可视化
秋天的怀念_David6 小时前
算法一千零一夜 · 第十三夜 幻方,武侠世界里的数学迷宫
java·程序人生·算法