在一个数组中找到所有数字的总和——排除数字13及其后面紧随的数字。

6
我想使用Java编写一个程序,它可以计算一个数组中所有数字的总和——但有个例外!因为数字13非常不吉利,所以我建议我们完全排除数字13以及直接跟在13后面的数字(如果有的话)。
这个程序名叫做sum13,以下是一些输入和输出示例: sum13([1,2,2,1]) = 6 这个很正常,没有13。 sum13([5, 13, 2]) = 5 排除了13和直接跟在13后面的数字。 sum13([13, 13]) = 0 数组只包含13,因此两个13都不包括在内。 sum13([1, 2, 13, 2, 1, 13]) = 4 这是一个稍微复杂一些的例子。
以下是我为sum13编写的代码:
public int sum13(int[] nums) {
  int sum = 0;
  for (int i = 0; i < nums.length; i++) {
    // we start by adding all the non-13s to the sum
    if (nums[i] != 13) sum += nums[i];
  }
  // now we go back and remove all the non-13s directly after a 13
  for (int j = 0; j < nums.length; j++) {
    // the outermost loop checks if the numbers are a 13
    if (nums[j] == 13 && j < nums.length - 1) {
      for (int k = j + 1; k < nums.length; k++) {
        // this loop checks that the number after the 13 is not a 13
        if (nums[k] != 13) {
          sum -= nums[k];
          break;
        }

      }
    }
  }
  return sum;
}

上述程序虽然能够正常工作,但是看起来相当混乱!

有没有更好的编写程序的方法,不需要包含多个循环和嵌套的 if 语句?


2
只是为了澄清语义:if语句不是循环,而只是一个条件语句。因此,在您上面发布的代码中,并没有4个嵌套的循环。 - user6073886
我明白了。你能否为我重新表达一下那个问题?很抱歉,我无法比那更清楚地表达它 :P - AnagramDatagram
5个回答

9

你使用i作为迭代器,当当前数字为13时,只需执行i++。这样,不仅不会将13加到总和中,还会跳过下一个值。

public int sum13(int[] nums) {
  int sum = 0;
  for (int i = 0; i < nums.length; i++) {
    // we start by adding all the non-13s to the sum
    if (nums[i] != 13){
     sum += nums[i];
    }
    else {
     i++;
    }
  }
 return sum;
}

那么我的理解是正确的吗?因为你在“else”循环中增加了“i”,所以它会在“for”循环中再次增加吗?也就是说,当我们遇到13时,“i”会增加两次吗? - AnagramDatagram
@NextTimeDW 是的:在你的例子中,1、2、13、2、1、13,当 i = 2 时,nums[i] 将会是13。然后我们进入 else 的情况,i 变成了3。当前循环结束后,我们增加 i 变成了4:我们已经跳过了直接在13后面的2。 - Kepotx
@NextTimeDW - 是的。(但它是一个“else块”,而不是“else循环”。循环是重复执行的东西。forwhiledo...while是循环。ifelseswitch则不是。) - T.J. Crowder
我明白了。不要介意我的问题用词不好,我只是在读软件工程的第一年:( - AnagramDatagram
2
@NextTimeDW - 我指出这一点的唯一原因是你显然是一个初学者,而且显然是一个会进步的人。 :-) (可悲的是,并非所有的初学者都会进步。)祝编码愉快! - T.J. Crowder
1
@NextTimeDW 不用担心,这已经足够清楚了。我们可以理解你犯了一些错误,毕竟StackOverflow也是为了学习而存在的。 - Kepotx

5

Kepotx展示了如何使用传统的for循环来完成。您也可以使用增强型for循环中的标志来完成:

public int sum13(int[] nums) {
    int sum = 0;
    boolean skipNext = false;
    for (int num : nums) {
        if (num == 13) {
            skipNext = true;
        } else {
            if (!skipNext) {
                sum += num;
            }
            skipNext = false;
        }
    }
    return sum;
}

提供的输入和期望输出的实时示例

希望有人熟悉流并向我们展示聪明的流方法... :-) ...而Malte Hartwig确实做到了(尽管他说,其中有一个不是最佳实践)。


这也是一个不错的解决方案!对我来说,比Kepotx的解决方案稍微难一些,但知道有多种方法可以做同样的事情总是好的 :) - AnagramDatagram
@TJ刚刚添加了一个基于流的答案,只是为了好玩,以防你仍然感兴趣 ;) - Malte Hartwig

3
使用AtomicBoolean可以大大缩短循环时间,当你使用IntStream进行总和计算时,循环更加简洁:
public static int sum13(int[] numbers)
{
    AtomicBoolean was13 = new AtomicBoolean(false);
    return IntStream.of(numbers)
                    .filter(i -> !was13.getAndSet(i == 13) && i != 13)
                    .sum();
}

最大的优势在于AtomicBoolean.getAndSet(boolean)允许我们检查前一个数字是否为13,并同时存储当前数字是否为13。

警告:正如Hulk在评论中指出的那样,改变流“外部”的对象状态并不是最佳实践。例如,在尝试使用并行流时,这可能会给你带来麻烦。在这里,可以使用自定义Collector避免使用外部状态,但这将使代码对于这个特定问题过于复杂。


2
可能使用流式处理是您能够做到的最好的选择,但由于这个问题来自一个初学者,因此最好包含一个警告,即通常应避免使用有状态的谓词。 - Hulk
@Hulk,感谢您指出这一点。我已经添加了一个警告。我考虑过添加一个非流版本,但它会变得更长,所以我认为增加难度(AtomicBoolean.getAndSet...)不值得比稍微短一点的代码。 - Malte Hartwig

0
一旦出现数字13,您需要跳过13和循环中的下一个字符。
 public class HelloWorld{

 public static void main(String []args){
    int arr[] = {1, 2, 4, 2, 1, 13,10};
    System.out.println(sum13(arr));
 }

 public static int sum13(int[] nums) {
  int sum = 0;
  int n = nums.length;
  for (int i = 0; i < n; i++) {
    if (nums[i] == 13){
        i=i+2;
    }

    if(i<n){
        sum += nums[i];
    }

  }
 return sum;
}



}

1
这个过程不必要这么复杂。Kepotx已经展示了如何通过操作循环索引来完成此操作。 - T.J. Crowder
2
它将起作用,因为在增加2之后计算总和。 - Ashu

0
为什么不使用 ArrayList 类呢?它已经实现了 iterator() 方法,代码可以像这样:
int sum13 (ArrayList<Integer> a) {
    Iterator<Integer> iter = a.iterator();
    int n;
    int sum=0;
    while (iter.hasNext() ) {
         n = iter.next(); 
         if (n !=13)
              sum = sum + n; /* n!=13 it will be added*/
         else if (iter.hasNext() )
              iter.next() /* n==13 not summing and skipping next */
    }
    return sum;
 }

方法签名已经给出,无法更改。对此我们深感抱歉。 - AnagramDatagram

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接