【问题标题】:Writing a string in a spiral在螺旋中写一个字符串
【发布时间】:2011-08-25 00:02:15
【问题描述】:

我最近参加了一家公司赞助的编码比赛,有一个我不明白的问题,关于它在问什么。

问题来了:

字符串“paypal 是更快、更安全的汇款方式”写成 从左上角开始的正方形内的顺时针螺旋图案: (您可能希望以固定字体显示此图案以提高可读性)。

   P A Y P A L
   F E R W A I
   A M O N Y S
   S D Y E T T
   R N E S O H
   E T S A F E

然后逐行读取: PAYPALFERWAIAMONYSSDYETTRNESOHETSAFE

编写接受字符串的代码,计算最小平方 包含它并返回转换后的字符串:

字符串转换(字符串文本);

示例:

    convert("paypalisthefastersaferwaytosendmoney") 
should return "paypalferwaiamonyssdyettrnesohetsafe"

您了解我们如何解决这个问题吗?

【问题讨论】:

  • 你不明白你被要求做什么或你怎么做?
  • 首先,我没有理解问题本身,一旦理解了问题,我就可以考虑第二部分。
  • 我个人认为玩弄代码是找出算法的最简单方法。例如,生成那个小字母网格将是一个好的开始。然后在其中生成螺旋化值,然后以输出格式提取螺旋值。

标签: java string algorithm grid


【解决方案1】:

我认为所写的问题应解释如下:

给定一个字符串,并希望将该字符串作为螺旋线写入方形网格。编写一个函数,找到可以容纳字符串的最小方格,将字符串按顺时针方向围绕网格旋转,将字符串写入网格,最后将行连接在一起。

例如,字符串“In a spiral”看起来像这样:

                I N A
In a spiral ->  A L S -> INAALSRIP
                R I P

要查看网格的来源,请注意,如果您是这样阅读的:

     I -> N -> A

               |
               v

     A -> L    S

     ^         |
     |         v

     R <- I <- P

您会返回初始文本,如果将行“INA”、“ALS”和“RIP”粘贴到单个字符串中,则会返回“INAALSRIP”。

让我们分别考虑每个问题。首先,要查看可以容纳文本的矩形的最小尺寸,您实际上是在寻找至少与文本长度一样大的最小完美正方形。要找到这个,您可以取字符串长度的平方根并将其四舍五入到最接近的整数。这为您提供了您想要的尺寸。但是,在您这样做之前,您需要从字符串中删除所有标点符号和空格字符(可能还有数字,具体取决于应用程序)。您可以通过遍历字符串并将确实是字母的字符复制到新缓冲区中来做到这一点。在接下来的内容中,我假设您已经完成了这项工作。

至于如何实际填充网格,有一个非常棒的方法可以做到这一点。直觉如下。当您从 n x n 网格开始时,您唯一的边界是网格的墙壁。每次你穿过网格放下字母并撞到墙上时,你只是从矩阵中刮掉了一行或一列。因此,您的算法可以通过跟踪第一个和最后一个合法列以及第一个和最后一个合法行来工作。然后,您从左到右走过顶行书写字符。完成后,然后增加第一个合法行,因为你不能再放任何东西了。然后,沿着右侧向下走,直到到达底部。完成后,您也可以将最后一列排除在外。例如,回顾我们的“螺旋形”示例,我们从一个空的 3x3 网格开始:

. . .
. . .
. . .

在顶部写下前三个字符后,剩下的是:

I N A
. . .
. . .

现在,我们需要将字符串的其余部分写入空白区域,从右上角开始向下移动。因为我们永远无法写回第一行,所以一种思考方式是考虑解决在较小的空间中以螺旋形式书写其余字符的问题

. . .
. . .

从左上角开始向下移动。

要真正将其实现为一种算法,我们需要在每个点跟踪一些事情。首先,我们需要在更新它们时存储世界的边界。我们还需要存储我们当前的写入位置,以及我们面临的方向。在伪代码中,这表示如下:

firstRow = 0, lastRow = N - 1 // Bounds of the grid
firstCol = 0, lastCol = N - 1

dRow = 0  // Amount to move in the Y direction
dCol = 1  // Amount to move in the X direction

row = 0   // Current position
col = 0

for each character ch in the string:
    Write character ch to position (row, col).

    // See if we're blocked and need to turn.
    If (row + dRow, col + dCol) is not contained in the rectangle [firstRow, lastRow] x [firstCol, lastCol]:
        // Based on which way we are currently facing, adjust the bounds of the world.
        If moving left,  increment firstRow
        If moving down,  decrement lastCol
        If moving right, decrement lastRow
        If moving up,    increment firstCol

        Rotate 90 degrees

    // Finally, move forward a step.
    row += dRow
    col += dCol

您可以使用线性代数中的一个技巧来实现 90 度转弯:将向量向左旋转 90 度,将其乘以 rotation matrix

|  0   1 |
| -1   0 |

所以你的新 dy 和 dx 由

给出
|dCol'| = |  0   1 | dCol = |-dRow|
|dRow'|   | -1   0 | dRow   | dCol|

所以你可以通过计算左转

temp = dCol;
dCol = -dRow;
dRow = temp;

另外,如果您知道数值为零的字符永远不会出现在字符串中,您可以使用 Java 初始化所有数组以在任何地方都保持零的事实。然后,您可以将 0 视为哨兵,意思是“继续前进是安全的”。该版本的(伪)代码如下所示:

dRow = 0  // Amount to move in the X direction
dCol = 1  // Amount to move in the Y direction

row = 0   // Current position
col = 0

for each character ch in the string:
    Write character ch to position (row, col).
    If (row + dRow, col + dCol) is not contained in the rectangle [0, 0] x [n-1, n-1]
             -or-
       The character at [row + dRow, col + dCol] is not zero:
        Rotate 90 degrees

   // Move forward a step
   row += dRow
   col += dCol

最后,一旦您将字符串写入螺旋,您可以通过一次一行地遍历行并将找到的所有字符连接在一起,将螺旋文本转换回字符串。

编辑:正如@Voo 指出的那样,您可以通过根本不实际创建多维数组而是将多维数组编码为一维数组来简化该算法的最后一步。这是一个常见的(而且很聪明!)技巧。例如,假设我们有一个这样的网格:

 0  1  2
 3  4  5
 6  7  8

那么我们可以用一维数组来表示这个

 0  1  2  3  4  5  6  7  8

这个想法是,给定 N x N 网格中的 (row, col) 对,我们可以通过查看位置 row * N + col 将该坐标转换为线性化数组中的相应位置。直观地说,这表示你在 y 方向上的每一步都相当于跳过一行中的所有 N 个元素,并且每一个水平步骤只是在线性化表示中水平移动一个步骤。

希望这会有所帮助!

【讨论】:

  • 这个不是很清楚,能提供清楚的解释吗?
  • 没有否决,我认为这是一个很好的答案 - 使用矩阵的答案怎么可能是别的(简单,优雅的数学应该是这样)? :D 我唯一要补充的是如何索引一维数组,就好像它是二维的一样。我确信我不必告诉你旧的 c“指针”算术东西有效,但我认为它对很多初学者都有帮助。
  • @Rachel - 我刚刚用更详细的描述更新了我的答案。有什么特别需要我帮忙的吗?我想帮忙,如果有不清楚的地方,我很乐意澄清。
  • 只是为了避免混淆,您“混淆”了 x 和 y。至少在 Java 和 co(基本上所有以 C 作为其影响/前体的语言)中,通常 arr[x][y] 表示第 x 行和第 y 列,而不是相反。太多的fortran? ;)
  • @Voo- (x, y) 我指的是位置 (x, y) 处的数组元素,使用在网格上排序 x 和 y 的标准方式。一个更好的方法是使用 row/col。我去更新一下。
【解决方案2】:

我用 Python 编写了一个实现,我认为它显示了一种类似工人的方法。尽管您将问题标记为 Java,但有时我认为对问题进行原型设计和了解问题是明智的,尤其是使用非常高级的动态语言的“面试问题”。语言本身就像运行的伪代码,这可以帮助您了解问题的形式或问题的形式。

线索就在这个人提出问题的方式中:

  • 有一个漂亮的字母形状的盒子。一个好的开始是问问自己,我如何编写制作一盒字母的代码。
  • 我将在什么数据结构(具有 x+(y*c) 查找的数组或二维数组)中存储字母框。
  • 如何将它们放入以及如何取出?

从将问题分解成更小的部分开始,您应该能够理解问题,然后开始制定答案。

它可能可以用更少的代码行来完成,但我觉得尽可能线性地完成它。这是一个不太擅长 python 的答案:

from math import *
import pprint

directions = [ (0,1),(1,0),(0,-1),(-1,0) ]  

def store_spiral(array,s,l):
    direction = 0
    dx = directions[direction][0]
    dy = directions[direction][1]
    x=0
    y=0
    for c in s:
        array[x][y] = c
        x = x +dx
        y = y +dy
        if (x >= l) or (y >= l) or (x<0) or (y<0):
            x=x-dx
            y=y-dy
            direction = (direction + 1) % 4
            dx = directions[direction][0]
            dy = directions[direction][1]            
            x=x+dx
            y=y+dy
        elif (array[x][y]!=''):
            x=x-dx
            y=y-dy
            direction = (direction + 1) % 4
            dx = directions[direction][0]
            dy = directions[direction][1]  
            x=x+dx
            y=y+dy


def convert(s):
    l = len(s)
    sl = int(ceil(sqrt(l)))
    # make empty 2d array of [ ['','', ... ], .... ]
    ar2 = [['' for i in range(sl)] for j in range(sl)]
    store_spiral(ar2,s,sl)
    x=''
    for ar in ar2:
        for l in ar:
            x=x+l
    return x

a = convert("paypalisthefastersaferwaytosendmoney")

print a

这里有一个想法如何制作更酷的版本,但它需要在这里生成一系列称为“限制”的值,即“转弯前步行的长度”。

from math import *
import pprint

# directions = East,South,West,North
directions = [ (0,1),(1,0),(0,-1),(-1,0) ]

x=0
y=-1

def store_spiral(array,s,l):
    global x
    global y
    direction = 0
    dx = directions[direction][0]
    dy = directions[direction][1]
    d=0
    n=0
    limits=[5,4,4,3,3,2,2,1,1,1,1]
    limit=limits[n]
    for c in s:
        d=d+1
        x=x+dx
        y=y+dy
        array[y+(x*l)]=c
        if d>limit and (limit>0):
            direction = (direction + 1) % 4
            dx = directions[direction][0]
            dy = directions[direction][1]
            n=n+1
            if n>=len(limits):
                break
            limit=limits[n]
            d=0        



def convert(s):
    l = len(s)
    sl = int(ceil(sqrt(l)))
    # make empty 2d array of [ ['','', ... ], .... ]
    ar = ['*' for i in range(l)]
    #try:
    store_spiral(ar,s,sl)
    #except:
    #  pass
    x=''
    n=0
    for l in ar:
            x=x+l
            print l,
            n=n+1
            if n==sl:
                n=0
                print
    return x

a = convert("paypalisthefastersaferwaytosendmoney")

print

print 'result: ',a

【讨论】:

    【解决方案3】:

    正方形的边长是正方形的平方根,其中正方形首先是长度。

    答案:

    • 以长度为整数
    • 求长度的平方根为浮点数,即根
    • 检查根的小数部分是否非零
    • 如果根的小数部分不为零,则根的整数部分加1,否则加0
    • 结果是一个整数
    • 这个数字是你的正方形每边有多大的答案
    • 实例化一个空方格,大小根据计算得出
    • 从左上角开始以“螺旋”方式访问每个插槽,从而填满正方形
    • 断言访问完成后源字符串中没有任何内容
    • 断言正方形的剩余未填充部分小于 (2x side size - 1)
    • 以从左到右、从上到下的顺序重新访问正方形以重建输出
    • 断言输出长度等于输入长度
    • 完成

    【讨论】:

      【解决方案4】:

      据我了解:

      你有

      ABCHIDGFE
      

      你把它转换成正方形(如果可能的话)

      A B C
      H I D
      G F E
      

      然后让字符串顺时针方向

      A B C D E F G H I
      

      并返回这个字符串

      如果无法解决问题,我不知道该怎么办。

      【讨论】:

      • 用一些特殊字符(如空格)填充任何非正方形长度的输入字符串?
      • @bdares,可能是。或者返回 null :)
      • 我认为你把它弄反了 - 字符串最初是未加扰的,你的工作就是加扰它。
      【解决方案5】:

      这是我对这个问题的理解。

      假设我们有字符串“hello world,这是我编写的第一个脚本,你今天好吗”

      这个字符串有 64 个字符。

      现在如果你看一下你给出的字符串,它有 36 个字符,其中的平方根是 6,因此每边有 6 个字母。

      所以上面的字符串有64个字符,其平方根为:8

      这意味着最小正方形需要每边有 8 个字母。

      此答案涉及“计算最小平方”要求背后的过程。

      【讨论】:

        【解决方案6】:

        //在c++中

        字符串转换(const string & s) { int len = s.size();

            //base case
            if (len == 0) return string("");
        
            // minimum square calculation
            int i = 1;
            while (i*i < len) ++i;
            //cout << "i=" << i << endl;
        
            //matrix initialization
            vector<vector<char> > matrix;
            matrix.resize(i);
            for (int j = 0; j < i; ++j)
                    matrix[j].resize(i);
            for (int j = 0; j < i; ++j)
                    for (int k = 0; k < i; ++k)
                            matrix[j][k] = ' ';
        
            //logic
            int r = 0, c = 0;
            bool right = true, down = false, left = false, up = false;      
            int curr_len = 0;
            int side = i - 1;
            while (curr_len < len)
            {
                    if (right)
                    {
                            for (int j = 1; (j <= side) && ((curr_len+j) <= len); ++j)
                            {
                                    matrix[r][c] = s[curr_len];
                                    //cout << curr_len << "|" << r << "|" << c << "|" << matrix[r][c] << "\n";
                                    ++c;
                                    ++curr_len;
                            }
        
                            right = false;
                            down = true;
                    }
        
                    if (down)
                    {
                            for (int j = 1; (j <= side) && ((curr_len+j) <= len); ++j)
                            {
                                    matrix[r][c] = s[curr_len];
                                    //cout << curr_len << "|" << r << "|" << c << "|" << matrix[r][c] << "\n";
                                    ++r;
                                    ++curr_len;
                            }
        
                            down = false;
                            left = true;
                    }
        
                    if (left)
                    {
                            for (int j = 1; (j <= side) && ((curr_len+j) <= len); ++j)
                            {
                                    matrix[r][c] = s[curr_len];
                                    //cout << curr_len << "|" << r << "|" << c << "|" << matrix[r][c] << "\n";
                                    --c;
                                    ++curr_len;
                            }
        
                            left = false;
                            up = true;
                    }
        
                    if (up)
                    {
                            for (int j = 1; (j <= side) && ((curr_len+j) <= len); ++j)
                            {
                                    matrix[r][c] = s[curr_len];
                                    //cout << curr_len << "|" << r << "|" << c << "|" << matrix[r][c] << "\n";
                                    --r;
                                    ++curr_len;
                            }
        
                            up = false;
                            right = true;
                            side = side - 2;
                            ++r; ++c;
                    }
            }
        
            stringstream ss;
        
            for (int j = 0; j < i; ++j)
            {
                    for (int k = 0; k < i; ++k)
                    {
                            ss << matrix[j][k];
                    }
            }
        
            return ss.str();
        

        }

        【讨论】:

          【解决方案7】:

          人们在上面的解决方案中使用了大量的嵌套循环和 if 语句。就个人而言,我发现从以下方面考虑如何做到这一点更清晰:

          direction
          current input position
          current row
          current column
          num rows to fill
          num cols to fill
          
          Fill right row 0 from column 0 to column 5.
          Fill down column 5 from row 1 to row 4.
          Fill left row 5 from column 4 to column 0
          Fill up column 0 from row 4 to row 1
          etc...
          

          这是一个经典的递归解决方案,如果您真的愿意,甚至可以针对分叉连接池进行修改。这个特定的解决方案实际上会根据输入调整输出网格大小,因此如果您从输入中修剪足够的字符,您可能会得到 5 行 x 6 列(尽管您总是可以将行修剪掉并只生成一个正方形很多空白)。

          public static void placeright(char output[][], char input[], int position, int row, int col, int numrows, int numcols) {
              for (int i=0;i<numcols && position < input.length;i++) {
                  output[row][col+i] = input[position++];
              }
              if (position < input.length){ 
                  placedown(output, input, position, row+1, col+numcols-1, numrows-1, numcols);
              }
          }
          public static void placedown(char output[][], char input[], int position, int row, int col, int numrows, int numcols) {
              for (int i=0;i<numrows && position < input.length;i++) {
                  output[row+i][col] = input[position++];
              }
              if (position < input.length){ 
                  placeleft(output, input, position, row+numrows-1, col-1, numrows, numcols-1);
              }
          }
          
          public static void placeleft(char output[][], char input[], int position, int row, int col, int numrows, int numcols) {
              for (int i=0;i<numcols && position < input.length;i++) {
                  output[row][col-i] = input[position++];
              }
              if (position < input.length){ 
                  placeup(output, input, position, row-1, col-numcols+1, numrows-1, numcols);
              }
          }
          public static void placeup(char output[][], char input[], int position, int row, int col, int numrows, int numcols) {
              for (int i=0;i<numrows && position < input.length;i++) {
                  output[row-i][col] = input[position++];
              }
              if (position < input.length){ 
                  placeright(output, input, position, row-numrows+1, col+1, numrows, numcols-1);
              }
          }
          
          
          public static void main( String[] args )
          {
              String input = "paypalisthefastersaferwaytosendmoney".toUpperCase();
              char chars[] = input.toCharArray();
          
              int sqrtceil = (int) Math.ceil(Math.sqrt(chars.length));
              int rows = sqrtceil;
              int cols = sqrtceil;
              while (cols*(rows-1) >= chars.length) {
                  rows--;
              }
              char output[][] = new char[rows][cols];
          
              placeright(output, chars, 0, 0, 0, rows, cols);
          
              for (int i=0;i<output.length;i++) {
                  for (int j=0;j<output[i].length;j++) {
                      System.out.print(output[i][j] + " ");
                  }
                  System.out.println();
              }       
          }
          

          【讨论】:

            【解决方案8】:

            试试这个

            package com.misc;
            
            public class SprintSpiral {
            
                public static void main(String[] args){
            
                    int xStart = 0;
                    int xEnd   = 3;
                    int yStart = 0;
                    int yEnd   = 3;
            
                    int[][] arr = new int[4][4];
            
                    arr[0][0]=1;
                    arr[1][0]=2;
                    arr[2][0]=3;
                    arr[3][0]=4;
                    arr[0][1]=5;
                    arr[1][1]=6;
                    arr[2][1]=7;
                    arr[3][1]=8;
            
                    arr[0][2]=9;
                    arr[1][2]=10;
                    arr[2][2]=11;
                    arr[3][2]=14;
                    arr[0][3]=15;
                    arr[1][3]=16;
                    arr[2][3]=17;
                    arr[3][3]=18;
            
            
                    for (int i = 0; i < 16; i++) {
            
                        for (int j = xStart; j <= xEnd; j++) {
                                System.out.println(arr[j][yStart]);
                        }
                        ++yStart;
                        for (int j = yStart; j <= yEnd; j++) {
                                System.out.println(arr[xEnd][j]);
                        }
                        xEnd--;
                        for (int j = xEnd; j >= xStart; j--) {
                                System.out.println(arr[j][yEnd]);
                        }
                        yEnd--;
                        for (int j = yEnd; j >= yStart; j--) {
                                System.out.println(arr[xStart][j]);
                        }
                        xStart++;
            
                    }
                }
            
            }
            

            【讨论】:

              【解决方案9】:

              首先用点字符填充一个 6x6 矩阵。然后将方向设置为 1。然后每次方向中的下一个字符不是点字符时更改方向。

              public class Spiral {
              static String phrase="paypalisthefastersaferwaytosendmoney";
              static int deltax,deltay,direction;
              
              public static void setDelta(){
              if(direction==1){
                  deltax=1;
                  deltay=0;
              }else if(direction==2){
                  deltax=0;
                  deltay=1;
              }else if(direction==3){
                  deltax=-1;
                  deltay=0;
              }else if(direction==4){
                  deltax=0;
                  deltay=-1;
              }
              }
              
              public static void main(String[] args) {
              int index=0,x,y,N=6;
              char[][] MATRIX=new char[N][N];
              for(y=0;y<N;y++){
                  for(x=0;x<N;x++) MATRIX[y][x]='.';
              }
              direction=1;
              setDelta();
              
              x=0;
              y=0;
                  while(index<phrase.length()){
                      while(x<N && x>=0 && y<N && y>=0){
                          MATRIX[y][x]=phrase.charAt(index);
                          System.out.print(MATRIX[y][x]);
                          index++;
              
                              if(direction==1 && MATRIX[y][x+1]!='.' || x+1==N-1) break;
                              if(direction==2 && MATRIX[y+1][x]!='.' && y<N-2) break;
                              if(direction==3 && MATRIX[y][x-1]!='.' || x==0) break;
                              if(direction==4 && MATRIX[y-1][x]!='.' && y>=0) break;
              
                          x+=deltax;
                          y+=deltay;
                      }
                      if(direction==4) direction=1;
                      else direction++;
                      setDelta();
              
                      x+=deltax;
                      y+=deltay;
                  }   
              }
              
              }
              

              【讨论】:

                【解决方案10】:

                计算最小平方很容易。您可以检查输入字符串中的字符数和最小平方大小 n*n。

                1*1= 1 
                2*2 = 4
                3*3 = 9
                

                所以你可以通过输入公式轻松找到 n

                n*n >= length(input string). 
                

                【讨论】:

                  【解决方案11】:

                  看起来PAYPALISTHEFASTERSAFERWAYTOSENDMONEY 是输入并且

                  P A Y P A L
                  F E R W A I
                  A M O N Y S
                  S D Y E T T
                  R N E S O H
                  E T S A F E
                  

                  是我的输出..

                  即使问题并没有明确说明最初提供算法。这是递归解决方案的伪代码:

                  convert(input):
                    spiral(out[][],input,0,0,sqrt(input.len))
                    return out.toString()
                  
                  spiral(out[][],input,ix,iy,size)
                    if size>0
                      //calculate the frame coords with starting indices ix,iy & size of the frame
                      place first 4*(size-1) chars on a frame on the ´out´ matrix
                      //recursive call to create inner frame
                      spiral(out,input.remainingString(),ix+1,iy+1,size-2)
                    else return
                  

                  在java中的实现:

                  public class PayPal {
                  
                      private enum Dir {
                  
                          RIGHT, DOWN, LEFT, UP;
                      }
                  
                      public String convert(String input) {
                          double dRoot = Math.sqrt(input.length());
                          int root;
                          if (Double.compare(dRoot, (int) dRoot) == 0) {
                              root = (int) dRoot;
                          } else {
                              root = (int) dRoot + 1;
                          }
                  
                          char[][] out = new char[root][root];
                  
                          spiral(out, 0, 0, root, input);
                          StringBuilder sb = new StringBuilder();
                  
                          for (char[] line : out) {
                              sb.append(line);
                          }
                  
                          return sb.toString();
                      }
                  
                      private void spiral(char[][] out, int i, int j, int size, String input) {
                          Dir direction = Dir.RIGHT;
                  
                          if (size > 0) {
                              if (size == 1) {
                                  out[i][j] = input.charAt(0);
                              } else {
                                  for (int k = 0; k < 4 * (size - 1); k++) {
                                      int di = (k != 0 && k % (size - 1) == 0 ? size - 1 : k % (size - 1));
                                      switch (direction) {
                                          case RIGHT:
                                              out[i][j + di] = input.charAt(k);
                                              break;
                                          case DOWN:
                                              out[i + di][j + size - 1] = input.charAt(k);
                                              break;
                                          case LEFT:
                                              out[i + size - 1][j + size - 1 - di] = input.charAt(k);
                                              break;
                                          case UP:
                                              out[i + size - 1 - di][j] = input.charAt(k);
                                              break;
                                      }
                                      if (k != 0 && (k % (size - 1) == 0)) //Change direction
                                      {
                                          direction = Dir.values()[direction.ordinal() + 1];
                                      }
                                  }
                              }
                              spiral(out, i + 1, j + 1, size - 2, input.substring(4 * (size - 1)));
                          } else {
                              return;
                          }
                      }
                  }
                  

                  【讨论】:

                  • 我不认为这回答了这个问题......你还没有提供解决问题的算法。
                  • 原来的问题并没有问算法,而是问题是什么
                  猜你喜欢
                  • 1970-01-01
                  • 2016-08-18
                  • 2023-03-28
                  • 1970-01-01
                  • 2012-01-12
                  • 2023-02-23
                  • 1970-01-01
                  • 1970-01-01
                  • 2010-09-28
                  相关资源
                  最近更新 更多