lintcode 中等题:Submatrix sum is 0 和为零的子矩阵
给定一个整数矩阵,请找出一个子矩阵,使得其数字之和等于0.输出答案时,请返回左上数字和右下数字的坐标。
给定矩阵
[
[1 ,5 ,7],
[3 ,7 ,-8],
[4 ,-8 ,9],
]
返回 [(1,1), (2,2)]
O(n3) 时间复杂度
解题
直接暴露求解,时间复杂度O(N2*M2 )
public class Solution {
/**
* @param matrix an integer matrix
* @return the coordinate of the left-up and right-down number
*/
public int[][] submatrixSum(int[][] matrix) {
// Write your code here
int[][] res = new int[2][2];
int row = matrix.length;
if(row ==0){
return res;
}
int col = matrix[0].length;
if(col ==0){
return res;
}
for(int i = 0;i< row ;i++){
for(int j = 0;j<col;j++){
int sum = matrix[i][j];
res[0][0]=i;
res[0][1]=j;
for(int n=i+1;n<row;n++){
for(int m=j+1;m<col;m++){
sum+=matrix[n][m];
if(sum==0){
res[1][0] = n;
res[1][1] = m;
break;
}
}
}
}
}
return res;
}
}
Java Code
总耗时: 8203 ms
在编程之美上,看到下面的方法:
1.先去(0,0)到(i,j)内的子矩阵的部分和,和存放中点(i,j)
2.根据上面的子矩阵,求解任意两点和为0的子矩阵
如何求解(0,0)到(i,j)内的子矩阵之和
(i-1,j-1) | (i-1,j) |
(i,j-1) | (i,j) |
如上图的子矩阵和的矩阵PS
PS[i-1][j-1] PS[i-1][j] PS[i][j-1]是已经求出的子矩阵的和
显然我们知道PS[i][j-1] = PS[i-1][j-1] + A[i][j-1] 这里的A是原始要求的矩阵,A[i][j-1]也就是(i,j-1)点的值
同理:PS[i-1][j] = PS[i-1][j-1] + A[i-1][j]
很显然:PS[i][j] = PS[i-1][j-1] + A[i-1][j] + A[i][j-1] + A[i][j]
将上面的含有A矩阵元素的值消掉就得到下面的矩阵:
PS[i][j] = PS[i][j-1] + PS[i-1][j] - PS[i-1][j-1]
对于第0行和第0类,我单独处理的
PS[0][0] = A[0][0]
第0行:PS[0][j] =PS[0][j-1] + A[0][j]
第0列:PS[i][0] =PS[i-1][0] + A[i][0]
非0行非0列按照上面的迭代求解
在求解任意两点和为0的子矩阵
我们求的是(i,j)到(m,n)的子矩阵
当m 或者n其中一个为0的时候单独考虑
其他情况 m、n都是非0的时候
要考虑 i、j是否是0的情况
如下:
int sum = 0;
if(i==0 && j==0){
sum = PS[m][n];
}else if(i==0 && j!=0){
sum = PS[m][n] - PS[m][j-1];
}else if(i!=0 && j==0){
sum = PS[m][n] -PS[i-1][n];
}else{
sum = PS[m][n] - PS[i-1][n] - PS[m][j-1] + PS[i-1][j-1];
}
这样计算的最终时间复杂度还是O(N2*M2)
最终程序
public class Solution {
/**
* @param matrix an integer matrix
* @return the coordinate of the left-up and right-down number
*/
public int[][] submatrixSum(int[][] matrix) {
// Write your code here
int[][] res = new int[2][2];
int row = matrix.length;
if(row ==0){
return res;
}
int col = matrix[0].length;
if(col ==0){
return res;
}
// 求解0 0 到i j的部分和
int PS[][] = new int[row][col];
PS[0][0] = matrix[0][0];
for(int i =1;i<row ;i++)
PS[i][0] =PS[i-1][0] + matrix[i][0];
for(int j =1;j<col ;j++)
PS[0][j] =PS[0][j-1] + matrix[0][j];
for(int i =1;i< row;i++){
for(int j=1;j<col;j++){
PS[i][j] = PS[i-1][j] + PS[i][j-1] - PS[i-1][j-1] + matrix[i][j];
}
}
// for(int i =0;i< row;i++){
// for(int j=0;j<col;j++){ // System.out.print(PS[i][j] +" ");
// }
// System.out.println();
// }
//对第0行和第0列单独判断
// 寻找i j 到 m n和为0的数组时间复杂度O(n*n*m*m)
//对第0行和第0列单独判断
// 第0列
for(int i =0;i< row ;i++){
res[0][0] = i;
res[0][1] = 0;
for(int j= i+1;j< row;j++){
if(i==0){
if(PS[j][0]==0){
res[1][0] = j;
res[1][1] = 0;
return res;
}
}
else if(PS[j][0]-PS[i-1][0] ==0){
res[1][0] = j;
res[1][1] = 0;
return res;
}
}
}
// 第0 行
for(int i =0;i< col ;i++){
res[0][0] = 0;
res[0][1] = i;
for(int j= i+1;j< col;j++){
if(i==0){
if(PS[0][j]==0){
res[1][0] = 0;
res[1][1] = j;
return res;
}
}
else if(PS[0][j]-PS[0][i-1] ==0){
res[1][0] = 0;
res[1][1] = j;
return res;
}
}
}
for(int i =0;i<row ;i++){
for(int j=0;j<col;j++){
res[0][0] = i;
res[0][1] = j;
for(int m = i+1;m<row; m++){
for(int n = j+1;n<col;n++){
int sum = 0;
if(i==0 && j==0){
sum = PS[m][n];
}else if(i==0 && j!=0){
sum = PS[m][n] - PS[m][j-1];
}else if(i!=0 && j==0){
sum = PS[m][n] -PS[i-1][n];
}else{
sum = PS[m][n] - PS[i-1][n] - PS[m][j-1] + PS[i-1][j-1];
}
if(sum==0){
res[1][0] = m;
res[1][1] = n;
return res; }
}
}
}
}
return res;
}
}
Java Code
总耗时: 7060 ms
上面参考的是编程之美
在九章的程序中,PS矩阵行列比原始的矩阵行列多1,在边界出来上不用那么复杂
同时在PS矩阵中求解任意两点的子矩阵时候,利用HashMap,对PS矩阵中任意两点的差值判断是否在HashMap中,当存在的时候就是答案了
public class Solution {
/**
* @param matrix an integer matrix
* @return the coordinate of the left-up and right-down number
*/
public int[][] submatrixSum(int[][] matrix) {
int[][] result = new int[2][2];
int M = matrix.length;
if (M == 0) return result;
int N = matrix[0].length;
if (N == 0) return result;
// pre-compute: sum[i][j] = sum of submatrix [(0, 0), (i, j)]
int[][] sum = new int[M+1][N+1];
for (int j=0; j<=N; ++j) sum[0][j] = 0;
for (int i=1; i<=M; ++i) sum[i][0] = 0;
for (int i=0; i<M; ++i) {
for (int j=0; j<N; ++j)
sum[i+1][j+1] = matrix[i][j] + sum[i+1][j] + sum[i][j+1] - sum[i][j];
}
for (int l=0; l<M; ++l) {
for (int h=l+1; h<=M; ++h) {
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int j=0; j<=N; ++j) {
int diff = sum[h][j] - sum[l][j];
if (map.containsKey(diff)) {
int k = map.get(diff);
result[0][0] = l; result[0][1] = k;
result[1][0] = h-1; result[1][1] = j-1;
return result;
} else {
map.put(diff, j);
}
}
}
}
return result;
}
}
Java Code
lintcode 中等题:Submatrix sum is 0 和为零的子矩阵的更多相关文章
- lintcode 中等题:k Sum ii k数和 II
题目: k数和 II 给定n个不同的正整数,整数k(1<= k <= n)以及一个目标数字. 在这n个数里面找出K个数,使得这K个数的和等于目标数字,你需要找出所有满足要求的方案. 样例 ...
- lintcode 中等题:A + B Problem A + B 问题
题目: 中等 A + B 问题 给出两个整数a和b, 求他们的和, 但不能使用 + 等数学运算符. 如果 a=1 并且 b=2,返回3 注意 你不需要从输入流读入数据,只需要根据aplusb的两个参数 ...
- lintcode 中等题:partition array 数组划分
题目 数组划分 给出一个整数数组nums和一个整数k.划分数组(即移动数组nums中的元素),使得: 所有小于k的元素移到左边 所有大于等于k的元素移到右边 返回数组划分的位置,即数组中第一个位置i, ...
- lintcode 中等题:permutations II 重复数据的全排列
题目 带重复元素的排列 给出一个具有重复数字的列表,找出列表所有不同的排列. 样例 给出列表 [1,2,2],不同的排列有: [ [1,2,2], [2,1,2], [2,2,1] ] 挑战 使用递归 ...
- lintcode 中等题:permutations 全排列
题目 全排列 给定一个数字列表,返回其所有可能的排列. 您在真实的面试中是否遇到过这个题? Yes 样例 给出一个列表[1,2,3],其全排列为: [ [1,2,3], [1,3,2], [2,1,3 ...
- lintcode 中等题:Divide Two Integers 两个数的除法
题目 两个整数相除 将两个整数相除,要求不使用乘法.除法和 mod 运算符. 如果溢出,返回 2147483647 . 样例 给定被除数 = 100 ,除数 = 9,返回 11 解题 15%的通过率 ...
- lintcode 中等题:和大于S的最小子数组
题目 和大于S的最小子数组 给定一个由 n 个整数组成的数组和一个正整数 s ,请找出该数组中满足其和 ≥ s 的最小长度子数组.如果无解,则返回 -1. 样例 给定数组 [2,3,1,2,4,3] ...
- lintcode 中等题:find the missing number 寻找缺失的数
题目 寻找缺失的数 给出一个包含 0 .. N 中 N 个数的序列,找出0 .. N 中没有出现在序列中的那个数. 样例 N = 4 且序列为 [0, 1, 3] 时,缺失的数为2. 注意 可以改变序 ...
- lintcode 中等题: Implement Trie
题目 Implement Trie Implement a trie with insert, search, and startsWith methods. 样例 注意 You may assu ...
随机推荐
- eclipse 4 rcp: java.lang.RuntimeException: No application id has been found.
错误详情: java.lang.RuntimeException: No application id has been found. at org.eclipse.equinox.internal. ...
- Ubuntu14.04忘记root密码的解决方法
电脑20多天没用忘记密码了,下面是在网上找到的一个解决办法,其它的和这个也大概相同.因为其中有些缺漏,没能给我解决问题.通过分析最终问题还是解决了,现解决方案的关键点记录一下.希望能方便到其它人. 1 ...
- java 语法糖
package syntax.autoCase; import java.util.Arrays; import java.util.List; public class autoCase { pub ...
- kibana去掉丑陋的basic验证框,用自定义验证代替。
最近在改写kibana,碰到了验证登录的问题.问题是这样子的,nginx设置了basic认证,然后客户端访问kibana的时候总是会弹出登录框,输入用户名和密码,现在要改写这个登陆框,用bootstr ...
- 相同的 birthday
Description Sometimes some mathematical results are hard to believe. One of the common problems is t ...
- android架构介绍
Android其本质就是在标准的Linux系统上增加了Java虚拟机Dalvik,并在Dalvik虚拟机上搭建了一个JAVA的application framework,所有的应用程序都是基于JAVA ...
- 深入PHP EOF(heredoc)用法详解
介绍下使用EOF heredoc方式,输出长段内容的方法, <?php $name = '姓名'; print <<<EOT <html> <head> ...
- bw R/3端配置 (转)
先检查一下两边系统的补丁:R3端如下, BW端按照老师的说法至少补丁要打到17,貌似我们是19,通过,这样做起事情来后顾无忧 登陆R3界面,SBIW这个是R3的最常用事务码,有关BW的所有东东都在他的 ...
- VBS基础篇 - 常量
常量:指的是在程序运行过程中其值保持不变的量,它用来保存固定不变的数值,字符串等常数 . 常量的定义:在vbscript中使用使用 Const 指令可以创建名称具有一定含义的字符串型或数值型常量,并给 ...
- Scrum10-22
Time:2013-10-22 Author:居玉皓 Things we have done since yesterday's meeting: 在今天的Scrum中,STORY1 开发前期准备工作 ...