一道面试题,看看怎么求解最好

shelinlin 2008-05-07 01:46:53
加精
给定一个数组,当中有正负数,求当中的一段“子数组”(即任意长度,连续的数字),使得这个“子数组”的和是所有“子数组”和中最大的,
如给定的数组为12, -8, 5, 66, -21, 0 ,35, -44,7,则最大的和的子数组为{12, -8, 5, 66, -21, 0 ,35},最大的和为89.
...全文
4615 225 打赏 收藏 转发到动态 举报
写回复
用AI写文章
225 条回复
切换为时间正序
请发表友善的回复…
发表回复
Anssin007 2010-07-07
  • 打赏
  • 举报
回复
思路:
1.从第一个正数开始,从左往右依次相加元素,当累加的值不小于零时就继续加,如果小于零,则停下,记录此时的累加值以及开始的位置和结束的位置;
2.再接着从下一个正数开始,重复第一步,如果这一段的累加值大于第一次的,则替换之前保存的累加值以及用新的开始位置和结束位置来替换之前保存的开始位置和结束位置;
3.遍历完整个数组,得到的开始位置和结束位置就是最大子数组的开始位置和结束位置。

代码:

/**
* CopyRight,2010 by XingYaan
*/
package src;

/**
* 给定一个数组,当中有正负数,求当中的一段“子数组”(即任意长度,连续的数字),
* 使得这个“子数组”的和是所有“子数组”和中最大的,
* 如给定的数组为12, -8, 5, 66, -21, 0 ,35, -44,7,
* 则最大的和的子数组为{12, -8, 5, 66, -21, 0 ,35},最大的和为89.
*
* @author Alvin
*/
public class MaxSubAryDemo {

public static int[] getMaxSub(int[] origin) {
int start = 0;
int end = 0;
int tmpStart = 0;
int maxSum = 0;
int tmpMaxSum = 0;
int plusNumCnt = 0;

int[] subAry = null;
for (int i =0; i < origin.length; i++) {
// 是正数
if (origin[i] > 0) {
plusNumCnt++;
if (plusNumCnt == 1) {
tmpStart = i;
}

tmpMaxSum += origin[i];
if (tmpMaxSum > maxSum) {
maxSum = tmpMaxSum;
end = i;
if (plusNumCnt == 1) {
start = tmpStart;
}
}
// 是负数或零
} else {
if (plusNumCnt > 0) {
tmpMaxSum += origin[i];
if (tmpMaxSum < 0) {
tmpMaxSum = 0;
plusNumCnt = 0;
}
}
}

}
subAry = new int[end - start + 1];
for (int i = 0; i < subAry.length; i++) {
subAry[i] = origin[start + i];
}
return subAry;

}


public static void main(String[] args) {
// int[] maxSubAry = getMaxSub(new int[]{12, -8, 5, 66, -21, 0, 35, -44, 7});
int[] maxSubAry = getMaxSub(new int[]{7, -44, 35, 0, -21, 66, 5, -8, 12});
for (int i : maxSubAry) {
System.out.print(i + " ");
}
}
}
Anssin007 2010-04-12
  • 打赏
  • 举报
回复
你TMD把在天涯的毛病带到这来了

[Quote=引用 204 楼 languagec 的回复:]
Java 版的脑残秀,看到就生气!
Java 版的脑残秀,看到就生气!
Java 版的脑残秀,看到就生气!
Java 版的脑残秀,看到就生气!
Java 版的脑残秀,看到就生气!
Java 版的脑残秀,看到就生气!
Java 版的脑残秀,看到就生气!
Java 版的脑残秀,看到就生气!
Java 版的脑残秀,看到就生气!
Java 版的脑残秀,看到就生气!
Java 版的脑残秀……
[/Quote]
Anssin007 2010-04-12
  • 打赏
  • 举报
回复
此算法第一前提就是错的,根本不能保证最大的子数组中一定包含原始数组中最大的元素。当原始数组两边都是负数时,基本上这个最大元素肯定要被放弃。

[Quote=引用 28 楼 yxh1226 的回复:]
思路:

1:找出数组中最大的数;

2:在原始数组的第一个数到最大的数的前一个数之间,从第一个非负数开始累加其后的数组元素,其结果一旦为负,放弃.再从下一个元素起到最大的数的前一个数之间,从第一个非负数开始累加其后的数组元素,其结果一旦为负,放弃;否则记下起始元素的下标a.


3: 在原始数组的最后一个数到最大的数的下一个数之间,从最后一个非负数开始累加其前的数组元素……
[/Quote]
Marty束 2009-12-10
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 jiangnaisong 的回复:]
引用楼主 shelinlin 的帖子:
给定一个数组,当中有正负数,求当中的一段“子数组”(即任意长度,连续的数字),使得这个“子数组”的和是所有“子数组”和中最大的,
如给定的数组为12, -8, 5, 66, -21, 0 ,35, -44,7,则最大的和的子数组为{12, -8, 5, 66, -21, 0 ,35},最大的和为89.

答:参考代码如下:
Java codepublicclass GetLongSeq {privatestaticint[] a={12,-8,5,66,-21,0,35,-44,7};//private static int[] a={-100,-100,-100,-100,100};privatestaticint ci,cj,cv;privatestaticvoid find()
{int head=0,tail=a.length-1;while(head<tail&& a[head]<0){head++;}//去掉头while(head<tail&& a[tail]<0){tail--;}//去掉尾int i=head,j=tail,temp=0;//当前已找到的子串的开始处,结束处与当前的最大值 ci=i;cj=i;cv=a[i];for(;i<=tail;i++)//从i开始进行连续子串找 {if(a[i]<0){continue;}//若开头的值小于0,显然不用考虑 temp=a[i];for(j=i+1;j<=tail;j++)
{
temp=temp+a[j];//当前子串的和if(temp>cv){//找到更大的,记下子串 ci=i;cj=j;cv=temp;
}
}//for(j)
}//for(i) }privatestaticvoid print()
{
System.out.print("{");for(int i=ci;i<=cj-1;i++)
{
System.out.print(a[i]+",");
}
System.out.print(a[cj]+"} 和="+cv);
}publicstaticvoid main(String[] args) {
find();
print();
}

}
运行结果:{12,-8,5,66,-21,0,35} 和=89
若是:{-100,-100,-100,-100,100},则结果:{100}和=100
程序思路:思路见程序注释。时间复杂性:O(n2),因为是双重循环。

[/Quote]
关注
myProMark 2009-12-06
  • 打赏
  • 举报
回复
Mark,51楼aipb2008
weijianliang 2009-10-15
  • 打赏
  • 举报
回复
学习
DoubleJoker163 2009-06-17
  • 打赏
  • 举报
回复
Java code


import java.util.ArrayList;


public class MumberSet {

//test
public static void main(String [] args){
int [] mumbers = {3,-12,12,-8,5,66,-21,0,35,-3,-44,100};
MumberSet aSet = new MumberSet(mumbers);
MumberSet bSet = aSet.getMaxSubSet();
System.out.println("A set is : " + aSet);
System.out.println("A set sum is : " + aSet.getSum());
System.out.println("Max sub set is : " + bSet);
System.out.println("Max sub set sum is : " + bSet.getSum());
}

private int sum = 0;
private ArrayList<Integer> list = new ArrayList<Integer>();

public MumberSet(){
}

public MumberSet(int mumber){
sum = mumber;
list.add(mumber);
}

public MumberSet(int [] mumber){
for(int i = 0 ; i < mumber.length ; i++){
sum = sum + mumber[i];
list.add(mumber[i]);
}
}

public int getSum(){
return sum;
}

public void addMumber(int mumber){
sum = sum + mumber;
list.add(mumber);
}

public void addMumberSet(MumberSet mumberSet){
sum = sum + mumberSet.sum;
list.addAll(mumberSet.list);
}

public void clear(){
sum = 0;
list.clear();
}

@SuppressWarnings("unchecked")
public MumberSet clone(){
MumberSet cloneSet = new MumberSet();
cloneSet.sum = sum;
cloneSet.list = (ArrayList<Integer>) list.clone();
return cloneSet;
}

public MumberSet getMaxSubSet(){
int n = list.size();
MumberSet temp = new MumberSet();
MumberSet maxSet = new MumberSet();
for(int i = 0 ; i < n ; i++){
temp.addMumber(list.get(i));
if(temp.getSum() < 0) temp.clear();
if(temp.getSum() > maxSet.getSum()) maxSet = temp.clone();
}
return maxSet;
}

public String toString(){
return list.toString();
}

}


测试数据

A set is : [3, -12, 12, -8, 5, 66, -21, 0, 35, -3, -44, 100]
A set sum is : 133
Max sub set is : [12, -8, 5, 66, -21, 0, 35, -3, -44, 100]
Max sub set sum is : 142
=========================================
A set is : [3, -12, 12, -8, 5, 66, -21, 0, 35, -3, -44]
A set sum is : 33
Max sub set is : [12, -8, 5, 66, -21, 0, 35]
Max sub set sum is : 89
=========================================
A set is : [-12, 12, -8, 5, 66, -21, 0, 35, -3, -44]
A set sum is : 30
Max sub set is : [12, -8, 5, 66, -21, 0, 35]
Max sub set sum is : 89
=========================================
A set is : [12, -8, 5, 66, -21, 0, 35, -3]
A set sum is : 86
Max sub set is : [12, -8, 5, 66, -21, 0, 35]
Max sub set sum is : 89
DoubleJoker163 2009-06-17
  • 打赏
  • 举报
回复
5 算法忘了讲原理
从a1开始,作为一个集合ai,然后向前合并
如果ai小于0,没有被最大集合合并的意义,应该剔除。
然后看对比一下,是不是最大集合。并记录最大集合。
集合a1>0才有被最大集合合并的意义,所以加下一个数。

6 缺陷
如果有多个最大子集,此算法只能找到第一个子集。大家可以改进一下

看来一下楼上的一些算法,真是屎。
怪不得有人不消,
根本没有oo思想,没有认真分析问题,难道都是初学者?
DoubleJoker163 2009-06-17
  • 打赏
  • 举报
回复
一个算法思想的问题

我定义一下题目:集合A{a1 , a2 , a3 ...... an}中,找出有序集合B{ai , a(i+1) , a(i+2) ...... aj},使B集合的和,是所有 有序集合中的最大值。

1 把问题看清楚:
把集合A分成多个集合,分法:相邻同符号的数为一个集合。
如{2,3,4,-2,-3,-4,21,23,-34,-12,1}变为{{2,3,4},{,-2,-3,-4},{21,23},{-34,-12},{1}}
得到A{C1 , C2 , C3 ...... Cn},看到这里,
应该知道怎么做了吧,其实A就是{+C1 , -C2 , +C3 ...... -Cn}。

2 算法(不用做上面写的那一步划分集合,ai为一个集合):

for(ai = a1 ; i < n ; i++){
if(ai < 0) ai=空set;
if(ai > a(max)) a(max)=ai;
ai = ai + a(i+1);
}

3 细节
(1)自定义一个集合类MumberSet
(2)MumberSet.getSum()//取得集合的和
(3)MumberSet.addMumber(mumber)//增加一个mumber元素//当然,你可以每加一个数,就马上整理sum的值,getSum就不要太搞cpu了
(4)MumberSet.addSet(mumberSet)//增加一个mumberSet
(5)MumberSet.getMaxSubSet()//取得最大顺序子串集合,算法用上面的就行了
(6)public MumberSet(int[] mumbers)//构造器

4 我没有测试过,谁有兴趣写一个来测试下,不行就告诉我
apache2008cai 2008-10-28
  • 打赏
  • 举报
回复
mark....
hnicypb 2008-08-21
  • 打赏
  • 举报
回复
题目都看不明白...
lookhang 2008-06-09
  • 打赏
  • 举报
回复
去看看《数据结构和算法分析》。。。
kString 2008-06-04
  • 打赏
  • 举报
回复
public Vector paixu(int[] s, int len) {

int k = 0;//存放结果集第1个数组元素下标
Vector result = new Vector();//返回结果集
for (int i = 0; i < s.length - len; i++) {
int sum = 0;
int mid = 0;
for (int j = i; j < i + len; j++) {
sum += s[j];

}

if (sum > mid) {
mid = sum;
k = i;
}
}

for (int i = k; i < k + len; k++) {
result.add(new Integer(s[k]));
}
return result;
}
cshnet7 2008-06-04
  • 打赏
  • 举报
回复
mark
suntao19830709 2008-06-04
  • 打赏
  • 举报
回复
后来发现,楼上写的漏洞很多,请牛人帮俺改改吧,哈哈
suntao19830709 2008-06-04
  • 打赏
  • 举报
回复

/**
*
*
* @time: 下午02:32:10
* @author Sun Tao(suntao19830709@gmail.com)
*/
public class ChildArray {

private static int[] base = { 12, -8, 5, 66, -21, 0, 35, -44, 7 };

public static void main(String[] args) {
int left = -1;
int right = base.length;
for(int i = 0; i<base.length; i++){
if(base[i] < 0){
int value = base[i];
for(int j = i-1; j >=0;j--){
value = value + base[j];
if(value >=0){
break;
}
}
if(value < 0){
left = i;
}
}

if(base[base.length - 1 - i] < 0){
int value = base[base.length - 1 - i];
for(int j = base.length - i; j < base.length ;j++){
value = value + base[j];
if(value >=0){
break;
}
}
if(value < 0){
right = base.length - 1 - i;
}
}
}
for(int i = left + 1; i < right ; i++){
System.out.print(base[i]+" ");
}
}
}

这是代码,时间复杂度基本就是 n*n,类似一个双重循环
suntao19830709 2008-06-04
  • 打赏
  • 举报
回复
分析,假设这个题目对于任意一个数组 {a1,a2,....a(n-1),an}有一个最大子数组的解。
假设是{ai.....aj}
那么:
1:a(i-1)是负数,a(j+1)也是负数
2:a1+a2+......+a(i-1) 一定是个负数,同理,a(j+1) + a(j+2)+....+an一定也是个负数
3:从a(i-1)起,依次加上它左边的数,始终找不到大于0的和
4:从a(j+1)起,依次加上它右边的数,始终找不到大于0的和
5:因此我们只要找到最靠近数组中间(非两端)的a(i-1)和a(j+1)即可

做起肯定不复杂了。
SunYaoZong 2008-06-03
  • 打赏
  • 举报
回复
强悍
btq123 2008-06-03
  • 打赏
  • 举报
回复
204楼的实在强。

刷得我眼睛都花了。
Sou2012 2008-06-02
  • 打赏
  • 举报
回复
实在是强
加载更多回复(200)

62,628

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧