Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【每日一题】- 2019-12-31 - 1260. 二维网格迁移 #256

Closed
azl397985856 opened this issue Dec 31, 2019 · 6 comments
Closed

【每日一题】- 2019-12-31 - 1260. 二维网格迁移 #256

azl397985856 opened this issue Dec 31, 2019 · 6 comments

Comments

@azl397985856
Copy link
Owner

@azl397985856 azl397985856 commented Dec 31, 2019

给你一个 n 行 m 列的二维网格 grid 和一个整数 k。你需要将 grid 迁移 k 次。

每次「迁移」操作将会引发下述活动:

位于 grid[i][j] 的元素将会移动到 grid[i][j + 1]。
位于 grid[i][m - 1] 的元素将会移动到 grid[i + 1][0]。
位于 grid[n - 1][m - 1] 的元素将会移动到 grid[0][0]。
请你返回 k 次迁移操作后最终得到的 二维网格。

示例 1:

输入:grid = [[1,2,3],[4,5,6],[7,8,9]], k = 1
输出:[[9,1,2],[3,4,5],[6,7,8]]
示例 2:

输入:grid = [[3,8,1,9],[19,7,2,5],[4,6,11,10],[12,0,21,13]], k = 4
输出:[[12,0,21,13],[3,8,1,9],[19,7,2,5],[4,6,11,10]]
示例 3:

输入:grid = [[1,2,3],[4,5,6],[7,8,9]], k = 9
输出:[[1,2,3],[4,5,6],[7,8,9]]

提示:

1 <= grid.length <= 50
1 <= grid[i].length <= 50
-1000 <= grid[i][j] <= 1000
0 <= k <= 100

题目地址: https://leetcode-cn.com/problems/shift-2d-grid/description/

@unclegem
Copy link

@unclegem unclegem commented Dec 31, 2019

Java题解 简单明了

由于题中数组长度范围较小,因此为了代码简洁直观,将该问题转化为一维数组的rotate问题最后存入List中,感兴趣的同学可以不需要申请临时一维数组,直接操作下标进行处理。

    public List<List<Integer>> shiftGrid(int[][] grid, int k) {
        
        int[] oneDim = new int[grid.length * grid[0].length];
        int idx = 0;
        for (int i = 0; i < grid.length; i++)
            for (int j = 0; j < grid[0].length; j++)
                oneDim[idx++] = grid[i][j];

        k %= oneDim.length;
        reverse(oneDim, 0, oneDim.length - k - 1);       
        reverse(oneDim, oneDim.length - k, oneDim.length - 1);
        reverse(oneDim, 0, oneDim.length - 1);  

        idx = 0;
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> oneRow = new ArrayList<>();
        for (int i = 0; i < oneDim.length; i++) {

            if (i > 0 && i % grid[0].length == 0) {

                res.add(oneRow);
                oneRow = new ArrayList<>();
            }

            oneRow.add(oneDim[i]);
        }
        res.add(oneRow);

        return res;
    }   

    public void reverse(int[] arr, int start, int end) {

        while (start < end) {

            int tmp = arr[start];
            arr[start] = arr[end];
            arr[end] = tmp;
            start++;
            end--;
        }
    }
@18sby
Copy link

@18sby 18sby commented Dec 31, 2019

/**
 * @param {number[][]} grid
 * @param {number} k
 * @return {number[][]}
 */

/*
  将二位数组转换为一维数组,之后操作一位数组转移k个位置,再转换为二维数组
*/
var shiftGrid = function(grid, k) {
  let len = grid.length;
  if (len === 0) return [];
  
  let rLen = grid[0].length;
  if (rLen === 0) return [];
  
  let totalLen = len * rLen, single = [];
  for (let i = 0; i < len; i++) {
    let row = grid[i];
    for (let j = 0; j < rLen; j++) {
      single.push( row[j] );
    }
  }
  
  k = k % totalLen;
  
  let pre = single.slice( totalLen - k ), suf = single.slice(0, totalLen - k);
  single = pre.concat( suf );
  
  let i = 0, j = 0;
  for (let k = 0, length = totalLen; k < length; k++) {
    if (j === rLen) {
      i += 1;
      j = 0;
    }
    grid[i][j] = single[k];
    j++;
  }
  
  return grid;
};
@ynzkai
Copy link

@ynzkai ynzkai commented Jan 9, 2020

python

def move_element(grid, k):
    n = len(grid)
    result = [([0]*n).copy() for x in range(0,n)]
    for i in range(0,n):
        for j in range(0,n):
            u = (i+(j+k)//n)%n
            v = (j+k)%n
            result[u][v] = grid[i][j]
    return result
@azl397985856
Copy link
Owner Author

@azl397985856 azl397985856 commented Jan 11, 2020

两种方法(Python Code)

@ynzkai 的代码是有问题的。 @unclegem 宝石叔的代码没问题,但是缺少说明,大家可能不明白,我来当一把”首席解释官“ @18sby 的代码虽然正确,但是使用了额外的空间。

纯暴力

我们直接翻译题目,没有任何hack的做法。

Python 代码:

from copy import deepcopy

class Solution:
    def shiftGrid(self, grid: List[List[int]], k: int) -> List[List[int]]:
        n = len(grid)
        m = len(grid[0])
        for _ in range(k):
            old = deepcopy(grid)
            for i in range(n):
                for j in range(m):
                    if j == m - 1:
                            grid[(i + 1) % n][0] = old[i][j]
                    elif i == n - 1 and j == m - 1:
                        grid[0][0] = old[i][j]
                    else:
                        grid[i][j + 1] = old[i][j]
        return grid

由于是easy,上述做法勉强可以过,我们考虑优化。

数学分析

我们仔细观察矩阵会发现,其实这样的矩阵迁移是有规律的。 如图:
image

因此这个问题就转化为我们一直的一维矩阵转移问题,LeetCode也有原题189. 旋转数组,同时我也写了一篇文章文科生都能看懂的循环移位算法专门讨论这个,最终我们使用的是三次旋转法,相关数学证明也有写,很详细,这里不再赘述。

LeetCode 真的是喜欢换汤不换药呀 😂

Python 代码:

#
# @lc app=leetcode.cn id=1260 lang=python3
#
# [1260] 二维网格迁移
#

# @lc code=start


class Solution:
    def shiftGrid(self, grid: List[List[int]], k: int) -> List[List[int]]:
        n = len(grid)
        m = len(grid[0])
        # 二维到一维
        arr = [grid[i][j] for i in range(n) for j in range(m)]
        # 取模,缩小k的范围,避免无意义的运算
        k %= m * n
        res = []
        # 首尾交换法

        def reverse(l, r):
            while l < r:
                t = arr[l]
                arr[l] = arr[r]
                arr[r] = t
                l += 1
                r -= 1
        # 三次旋转
        reverse(0, m * n - k - 1)
        reverse(m * n - k, m * n - 1)
        reverse(0, m * n - 1)
        # 一维到二维
        row = []
        for i in range(m * n):
            if i > 0 and i % m == 0:
                res.append(row)
                row = []
            row.append(arr[i])
        res.append(row)

        return res

# @lc code=end
@ynzkai
Copy link

@ynzkai ynzkai commented Jan 16, 2020

审题不严了,考虑成n*n的网格了,改一下就对了。

def shiftGrid(grid, k):
    n = len(grid)
    m = len(grid[0])
    result = [([0]*m).copy() for x in range(0,n)]
    for i in range(0,n):
        for j in range(0,m):
            u = (i+(j+k)//m)%n
            v = (j+k)%m
            result[u][v] = grid[i][j]
    return result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.