Lintcode 29,30,31,32

本文探讨了多个编程问题,涉及栈的应用、递归深度、动态规划解决不同路径(包括有障碍、权重)、背包问题(0/1、完全、多重),以及利用集合和迭代优化求解。通过实例展示了如何在有限栈空间下优化算法并解决复杂问题。
109 · 数字三角形
public class Solution {
    public int minimumTotal(int[][] triangle) {
        int n = triangle.length;
        if (n == 0) return -1;
        
        for (int i = n - 2; i >= 0; i --) {
            for (int j = 0; j <= i; j ++) {
                triangle[i][j] += Math.min(triangle[i + 1][j], triangle[i + 1][j + 1]);
            }
        }
        return triangle[0][0];
    }
}
public class Solution {
    public int minimumTotal(int[][] triangle) {
        int n = triangle.length;
        if (n == 0) return -1;
        
        //因为最后一行最后一列需要和右边的邻居比,所以这里声明数组,长度要加1
        int [] res = new int[n + 1];        

        for (int i = n - 1; i >= 0; i --) {
            for (int j = 0; j <= i; j ++) {
                res[j] = Math.min(res[j], res[j + 1]) + triangle[i][j];
            }
        }
        return res[0];
    }
}
关于29章17页:栈的容量是有限的,递归次数越多,消耗的栈空间越多,栈空间用完了就会溢出
114 · 不同的路径
public class Solution {
    public int uniquePaths(int m, int n) {
        int f[][] = new int[m + 1][n + 1];
        f[0][1] = 1;

        for (int i = 1; i <= m; i ++) {
            for (int j = 1; j <= n; j ++) {
                f[i][j] = f[i - 1][j] + f[i][j - 1];
            }
        }
        return f[m][n];
    }
}
public class Solution {
    public int uniquePaths(int m, int n) {
        int f[] = new int[n + 1];
        f[1] = 1;

        for (int i = 1; i <= m; i ++) {
            for (int j = 1; j <= n; j ++) {
                f[j] += f[j - 1];
            }
        }
        return f[n];
    }
}
115 · 不同的路径 II
public class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int n = obstacleGrid.length;
        int m = obstacleGrid[0].length;

        int f[] = new int [m];
        f[0] = 1;
        
        for (int i = 0; i < n; i ++) {
            if (obstacleGrid[i][0] == 1) f[0] = 0;      //有障碍方案数为1
            for (int j = 1; j < m; j ++) {
                if (obstacleGrid[i][j] == 1) f[j] = 0;
                else f[j] += f[j - 1];
            }
        }

        return f[m - 1];
    }
}
679 · 不同的路径 III
public class Solution {
    public int uniqueWeightedPaths(int[][] grid) {
        int n = grid.length;
        int m = grid[0].length;
        if (n == 0 || m == 0) return 0;        

        Set<Integer>[][] f = new HashSet[n][m];

        for (int i = 0; i < n; i ++) {
            for (int j = 0; j < m; j ++) {
                f[i][j] = new HashSet();
                if (i == 0 && j == 0) {
                    f[i][j].add(grid[i][j]);
                }
                else {
                    if (i != 0) {
                        for (int num : f[i - 1][j]) {
                            f[i][j].add(num + grid[i][j]);
                        }
                    }
                    if (j != 0) {
                        for (int num : f[i][j - 1]) {
                            f[i][j].add(num + grid[i][j]);
                        }
                    }
                }
            }
        }

        int ans = 0;
        for (int num : f[n - 1][m - 1]) ans += num;

        return ans;
    }
}
630 · 骑士的最短路径II
public class Solution {
     public int shortestPath2(boolean[][] grid) {
		int n = grid.length;
		int m = grid[0].length;
		if (n == 0 || m == 0) return -1;

		int[] dx = {-2, -1, 1, 2};
		int[] dy = {-1, -2, -2, -1};	

		int f[][] = new int[n][m];
		f[0][0] = 1;						//起点

	   	for (int j = 0; j < m; j ++) {		//从左到右
			for (int i = 0; i < n; i ++) {
				if (grid[i][j]) continue;	//有障碍物

			   	for (int k = 0; k < 4; k ++) {
					int x = i + dx[k];
					int y = j + dy[k];					
				   	if (x < 0 || y < 0 || x >= n || f[x][y] == 0) continue;
					
					if (f[i][j] == 0) f[i][j] = f[x][y] + 1;
					else f[i][j] = Math.min(f[i][j], f[x][y] + 1);
			   	}
		   	}
	   	}

	   	return f[n - 1][m - 1] - 1;
    }
}
116 · 跳跃游戏
public class Solution {
    public boolean canJump(int[] A) {
        int n = A.length;
        if (n == 0) return true;

        int maxx = 0;          //能够到达的最远处
        for (int i = 0; i < n; i ++) {
            if (i <= maxx) {
                maxx = Math.max(maxx, i + A[i]);
            }
        }
        return maxx >= n - 1;
    }
}
92 · 背包问题
  • 二维数组
public class Solution {
    public int backPack(int m, int[] A) {
        int n = A.length;

        int f[][] = new int[n + 1][m + 1];  //前i件物品放入容量为j的背包,最多能装f[i][j]
        for (int i = 1; i <= n; i ++) {
            int t = A[i - 1];				//第i件物品的重量是A[i - 1]
            for (int j = 0; j <= m; j ++) {         
                if (t > j) f[i][j] = f[i - 1][j];
                else f[i][j] = Math.max(f[i - 1][j], f[i - 1][j - t] + t);
            }
        }

        return f[n][m];
    }
}
  • 一维数组
public class Solution {
    public int backPack(int m, int[] A) {
    	int n = A.length;
    	
        int f[] = new int[m + 1];		//前i件物品放入容量为j的背包,最多能装f[j]
        for (int i = 1; i <= n; i ++) {
            int t = A[i - 1];			//第i件物品的重量是A[i - 1]
            for (int j = m; j >= t; j --) {      		
                f[j] = Math.max(f[j], f[j - t] + t);
            }
        }

        return f[m];
    }
}
  • 一维 + 或运算
public class Solution {
    public int backPack(int m, int[] A) {
    	int n = A.length;
    	
        int f[] = new int[m + 1];       //如果前i件物品可以装出j的容量,则f[j] = 1        
        f[0] = 1;
        
        for (int i = 1; i <= n; i ++) {
            int t = A[i - 1];           //第i件物品的重量是A[i - 1]
            for (int j = m; j >= t; j --) {  
                f[j] |= f[j - t];
            }
        }

        int ans = 0;
        for (int i = m; i >= 0; i --) {
            if (f[i] == 1) {
                ans = i;
                break;
            }
        }
        return ans;
    }
}
724 · 最小划分
public class Solution {
    public int findMin(int[] nums) {
        int n = nums.length;
        int m = 0;
        for (int i = 0; i < n; i ++) m += nums[i];

        int f[] = new int[m + 1];

        for (int i = 1; i <= n; i ++) {
            int t = 2 * nums[i - 1];
            for (int j = m; j >= t; j --) {
                f[j] = Math.max(f[j], f[j - t] + t);
            }
        }

        return m - f[m];
    }
}
125 · 背包问题(二)
public class Solution {
    public int backPackII(int m, int[] A, int[] V) {
        int n = A.length;

        int f[] = new int[m + 1];
        for (int i = 1; i <= n; i ++) {
            for (int j = m; j >= A[i - 1]; j --) {
                f[j] = Math.max(f[j], f[j - A[i - 1]] + V[i - 1]);
            }
        }

        return f[m];
    }
}
440 · 背包问题 III

32章26页,这是完全背包,并不是多重背包

public class Solution {
    public int backPackIII(int[] A, int[] V, int m) {
       int n = A.length;

        int f[] = new int[m + 1];
        for (int i = 1; i <= n; i ++) {
            for (int j = A[i - 1]; j <= m; j ++) {
                f[j] = Math.max(f[j], f[j - A[i - 1]] + V[i - 1]);
            }
        }

        return f[m];
    }
}
562 · 背包问题 IV
public class Solution {
    public int backPackIV(int[] nums, int target) {
        int n = nums.length;
        int m = target;

        int f[] = new int[m + 1];
        f[0] = 1;

        for (int i = 1; i <= n; i ++) {
            for (int j = nums[i - 1]; j <= m; j ++) {
                f[j] += f[j - nums[i - 1]];
            }
        }

        return f[m];
    }
}
563 · 背包问题 V
public class Solution {
    public int backPackV(int[] nums, int target) {
        int n = nums.length;
        int m = target;

        int f[] = new int[m + 1];
        f[0] = 1;

        for (int i = 1; i <= n; i ++) {
            for (int j = m; j >= nums[i - 1]; j --) {
                f[j] += f[j - nums[i - 1]];
            }
        }

        return f[m];        

    }
}
### LintCode 31 题目解析与解决方案 LintCode 31 题目名称为“数组划分”(Partition Array),其目标是将一个整数数组按照给定的整数 `k` 进行划分,使得所有小于 `k` 的元素位于数组的左侧,所有大于等于 `k` 的元素位于数组的右侧。最终需要返回划分后左侧部分的长度。 #### 题目描述 给定一个整数数组 `nums` 和一个整数 `k`,要求重新排列数组中的元素,使得所有小于 `k` 的元素出现在数组的左侧,所有大于等于 `k` 的元素出现在数组的右侧。返回划分后左侧部分的长度。 --- #### 解题思路 此问题可以通过双指针法高效解决。核心思想是使用两个指针分别从数组的两端开始扫描: - 左指针 `left` 从左向右寻找第一个大于等于 `k` 的元素。 - 右指针 `right` 从右向左寻找第一个小于 `k` 的元素。 - 当找到满足条件的两个元素时,交换它们的位置。 - 重复上述过程,直到两个指针相遇。 这种方法的时间复杂度为 O(n),空间复杂度为 O(1)。 --- #### 实现代码 以下是基于 C++ 和 Java 的实现代码: ```cpp class Solution { public: /** * @param nums: The integer array you should partition * @param k: An integer * @return: The index after partition */ int partitionArray(vector<int> &nums, int k) { if (nums.empty()) return 0; int left = 0, right = nums.size() - 1; while (left <= right) { while (left <= right && nums[left] < k) left++; while (left <= right && nums[right] >= k) right--; if (left <= right) { swap(nums[left], nums[right]); left++; right--; } } return left; } }; ``` ```java public class Solution { /** * @param nums: The integer array you should partition * @param k: An integer * @return: The index after partition */ public int partitionArray(int[] nums, int k) { if (nums.length == 0) return 0; int left = 0, right = nums.length - 1; while (left <= right) { while (left <= right && nums[left] < k) left++; while (left <= right && nums[right] >= k) right--; if (left <= right) { int temp = nums[left]; nums[left] = nums[right]; nums[right] = temp; left++; right--; } } return left; } } ``` --- #### 示例分析 **输入:** ```plaintext nums = [3, 2, 2, 1], k = 2 ``` **输出:** ```plaintext 2 ``` **解释:** 经过划分后,数组可能变为 `[1, 2, 2, 3]` 或其他等效形式,其中前两个元素均小于 `k=2`。 --- #### 复杂度分析 - **时间复杂度**:O(n),其中 n 是数组的长度。每个元素最多被访问两次(一次由左指针,一次由右指针)。 - **空间复杂度**:O(1),算法仅使用了常量级别的额外空间。 --- #### 注意事项 1. 初始时需检查数组是否为空,若为空则直接返回 0。 2. 循环条件为 `left <= right`,确保在指针相遇时仍能正确处理最后一个待交换的元素。 3. 在每次交换后,记得更新指针位置(`left++` 和 `right--`)以避免死循环。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值