从零学算法6

13 篇文章 0 订阅
11 篇文章 0 订阅

6. Z 字形变换
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下:

	P   A   H   N
	A P L S I I G
	Y   I   R

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“PAHNAPLSIIGYIR”。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
输入:s = “PAYPALISHIRING”, numRows = 3
输出:“PAHNAPLSIIGYIR”
示例 2:
输入:s = “PAYPALISHIRING”, numRows = 4
输出:“PINALSIGYAHRPI”
解释:

P     I    N
A   L S  I G
Y A   H R
P     I

示例 3:
输入:s = “A”, numRows = 1
输出:“A”
提示:
1 <= s.length <= 1000
s 由英文字母(小写和大写)、‘,’ 和 ‘.’ 组成
1 <= numRows <= 1000

  • 我的原始人解法(可略):模拟,找到变换规律。首先 row 为 1 返回 s 即可;然后用字符二维数组 res 记录变换后的形状,比如例子 2,可以分为 3 列一组,每一列的长度为 numRows,1,1,numRows 为其他时同理,可分为 numRows - 1 列一组,每一组长度为 numRows,1,1。根据这个规律,我们可以得到所需的列有多少列。
  • 分组示意图
  •  P        	I    			N
     A   L    	S  I G
     Y A      	H R
     P        	I
    
  • 然后就是遍历 s 根据规律将字符加入 res,先在当前列从上到下加 numRows 个字符,然后将字符加入下一列的倒数第二行,下一列倒数第三行…直到下一列的第二行,就完成一组,之后同理
  •   public String convert(String s, int numRows) {
          if(numRows == 1)return s;
          int len = s.length();
          int numCols = getNumCols(len, numRows);
          char[][] res = new char[numRows][numCols];
          int col = 0;
          int i = 0;
          StringBuilder sb = new StringBuilder();
          while(col < numCols){
              int row = 0;
              // 先加 x 列一组中的第一列
              while(i < len && row < numRows){
                  res[row++][col] = s.charAt(i++);
              }
              col++;
              // 剩下的行数从倒数第二行开始
              row = numRows - 1 - 1;
              // 再加 x 列一组的剩下列,每一列有一个字符
              while(i < len && row > 0){
                  res[row--][col++] = s.charAt(i++);
              }
          }
          for(char[] cs : res){
              for(char c : cs){
                  if(c != '\u0000')sb.append(c);
              }
          }
          return sb.toString();
      }
      // 计算有几列
      public int getNumCols(int len, int numRows){
          int[] nums = new int[numRows - 1];
          Arrays.fill(nums, 1);
          nums[0] = numRows;
          int numCols = 0;
          while(len > 0){
              for(int i = 0; i < nums.length; i++){
                  len -= Math.min(len, nums[i]);
                  numCols++;
                  if(len == 0)break;
              }
          }
          return numCols;
      }
    
  • 他人解法:其实观察过后会发现,字符所放的行数就是从 0 ~ numRows-1 -> numRows-1 ~ 0 -> 0 ~ numRows-1... 循环变动,我们定义一个 stringBuilder 数组 rows,跟随行变化规律拼接字符即可。
  • 比如 “abcde”,numRows = 3,就是把 a 加入第一行, 得到 rows[0] = a,然后把 b 加入第二行 rows[1] = b -> rows[2] = c -> rows[1] = bd -> rows[0] = ae,最终把每一行的结果拼接到一起:ae + bd + c = aebdc
  •   public String convert(String s, int numRows) {
          if(numRows == 1)return s;
          List<StringBuilder> rows = new ArrayList<StringBuilder>();
          for(int i = 0; i < numRows; i++) rows.add(new StringBuilder());
          // flag: 行变化规律标志,控制 rowIndex 递增还是递减
          int rowIndex = 0, flag = -1;
          for(char c : s.toCharArray()) {
              rows.get(rowIndex).append(c);
              // 行到顶部就该往下递增,到底部就该往上递减,所以改变 flag
              if(rowIndex == 0 || rowIndex == numRows - 1)flag = -flag;
              rowIndex += flag;
          }
          StringBuilder res = new StringBuilder();
          for(StringBuilder row : rows) res.append(row);
          return res.toString();
      }
    
  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
从零开始学习贪心算法需要掌握以下几个点: 1. 贪心算法的定义:贪心算法是指在问题求解过程中,总是做出当前看来最好的选择,而不考虑整体最优解。贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。 2. 贪心算法的解题步骤:建立数学模型描述问题,将问题分解为若干个子问题,对每个子问题求解得到局部最优解,将局部最优解合成原问题的最优解。 3. 贪心算法与动态规划的关系:贪心算法是动态规划的一种特例。贪心算法不需要知道一个节点所有子树的情况,只需要选择当前问题的最优解路径,一直走到底即可。而动态规划需要自底向上构造子问题的解。 4. 活动选择问题是贪心算法的一个经典例子。在活动选择问题中,需要在同一天使用同一个教室举行多个活动,要求选择尽可能多的活动不冲突地进行。 综上所述,从零开始学习贪心算法,要理解贪心算法的定义和特点,掌握贪心算法的解题步骤,了解贪心算法与动态规划的关系,并通过经典例子如活动选择问题来实践和加深对贪心算法的理解。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [从0开始学贪心算法](https://blog.csdn.net/weixin_45024585/article/details/107515191)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [leetcode338-leetcode:从零开始](https://download.csdn.net/download/weixin_38750644/19950444)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [从零开始学贪心算法](https://blog.csdn.net/qq_32400847/article/details/51336300)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值