leetcode 64.最小路径和(minimum path sum)c语言

1.description

https://leetcode-cn.com/problems/minimum-path-sum/description/

给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

示例:

输入: [ [1,3,1], ⁠ [1,5,1], ⁠ [4,2,1] ] 输出: 7 解释: 因为路径 1→3→1→1→1 的总和最小。

2.solution

回溯法加备忘录在倒数第2个case超时了

void solve(int i, int j, int dist, int gridSize, int gridColSize, int **grid, int *p, int **mem){
          
   
    if(i==gridSize-1 && j==gridColSize || i==gridSize && j==gridColSize-1){
          
   
        if(dist < *p){
          
   
            *p = dist;
        }
        return;
    }

    if(i<gridSize && j<gridColSize){
          
   
        if(dist+grid[i][j] > mem[i][j]) return;
        mem[i][j] = dist+grid[i][j];
        solve(i+1, j, dist+grid[i][j], gridSize, gridColSize, grid, p, mem); //向下移动
        solve(i, j+1, dist+grid[i][j], gridSize, gridColSize, grid, p, mem); //向右移动
    }
}

int minPathSum(int** grid, int gridSize, int* gridColSize){
          
   
    int mind = INT_MAX; // 最短路径
    int *p = &mind; // 用于修改mind

    int **mem = (int**)malloc(gridSize*sizeof(int*));
    for(int i=0; i<gridSize; ++i){
          
   
        mem[i] = (int*)malloc((*gridColSize)*sizeof(int));
        memset(mem[i], 127, (*gridColSize)*sizeof(int));
    }

    solve(0, 0, 0, gridSize, *gridColSize, grid, p, mem);

    return mind;
}

换用动态规划:

#define min(a,b) (((a) < (b)) ? (a) : (b))

int minPathSum(int** grid, int gridSize, int* gridColSize){
          
   
    int **dp = (int**)malloc(gridSize*sizeof(int*));
    for(int i=0; i<gridSize; ++i){
          
   
        dp[i] = (int*)malloc(*gridColSize*sizeof(int));
    }

    int sum = 0;
    // 初始化dp第一行
    for(int i=0; i<*gridColSize; ++i){
          
   
        sum += grid[0][i];
        dp[0][i] = sum;
    }
    sum = 0;
    // 初始化dp第一列
    for(int i=0; i<gridSize; ++i){
          
   
        sum += grid[i][0];
        dp[i][0] = sum;
    }

    for(int i=1; i<gridSize; ++i){
          
   
        for(int j=1; j<*gridColSize; ++j){
          
   
            dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1]);
        }
    }

    int res = dp[gridSize-1][*gridColSize-1];

    // free
    for(int i=0; i<gridSize; ++i){
          
   
        if(dp[i]){
          
   
            free(dp[i]);
        }
    }

    if(dp){
          
   
        free(dp);
    }

    return res;
}

将二维的状态表压缩成二维的vector

#define min(a,b) (((a) < (b)) ? (a) : (b))

static inline void swap(int **p, int **q){
          
   
    int *tmp = *p;
    *p = *q;
    *q = tmp;
}

int minPathSum(int** grid, int gridSize, int* gridColSize){
          
   
    int *pre = (int*)malloc(*gridColSize*sizeof(int));
    int *cur = (int*)malloc(*gridColSize*sizeof(int));

    pre[0] = grid[0][0];
    for(int i=1; i<*gridColSize; ++i){
          
   
        pre[i] = pre[i-1] + grid[0][i];
    }

    for(int i=1; i<gridSize; ++i){
          
   
        cur[0] = pre[0] + grid[i][0];
        for(int j=1; j<*gridColSize; ++j){
          
   
            cur[j] = grid[i][j] + min(pre[j], cur[j-1]);
        }
        swap(&pre, &cur);
    }
 
    int res = pre[*gridColSize-1];
    
    // free
    if(pre){
          
   
        free(pre);
    }

    if(cur){
          
   
        free(cur);
    }
    
    return res;
}

进一步压缩到一维vector

#define min(a,b) (((a) < (b)) ? (a) : (b))

int minPathSum(int** grid, int gridSize, int* gridColSize){
          
   
    // 将二维的状态表压缩成了一维的vector
    int *dp = (int*)malloc(*gridColSize*sizeof(int));

    dp[0] = grid[0][0];
    for(int i=1; i<*gridColSize; ++i){
          
   
        dp[i] = dp[i-1] + grid[0][i];
    }

    for(int i=1; i<gridSize; ++i){
          
   
        dp[0] = dp[0] + grid[i][0];
        for(int j=1; j<*gridColSize; ++j){
          
   
            dp[j] = grid[i][j] + min(dp[j], dp[j-1]);
        }
    }

    int res = dp[*gridColSize-1];
    
    if(dp){
          
   
        free(dp);
    }
    
    return res;
}
经验分享 程序员 微信小程序 职场和发展