【问题标题】:Counting The Number of Valleys [duplicate]计算山谷的数量[重复]
【发布时间】:2019-09-30 15:50:45
【问题描述】:

我在hackerRank上做一个问题,问题是:

问题陈述

这里我们必须计算XYZ 人访问的山谷数量。

山谷是低于海平面的一系列连续台阶,从海平面下降开始,到海平面上升结束。

向上一级为U,向下一级为D。我们将以字符串的形式给出XYZ人走过的步数加上上下,即

UUDDUDUDDUU

示例输入

8
UDDDUDUU

样本输出

1

说明

如果我们将 _ 表示为海平面,向上表示为 /,向下表示为 \,则 Gary 的远足可以绘制为:

_/\      _
   \    /
    \/\/

他进出一个山谷。

我写的代码不行

static int countingValleys(int n, String s) {    
    int count = 0;
    int level = 0;
    String[] arr = s.split("");
    for(int i = 0; i<n;i++){
        if(arr[i] == "U"){
            level++;
        } else{
            level--;
        }    
        if(level==0 && arr[i]=="U"){
            count++;
        }
    }
    return count;
}

但是我找到了另一个解决方案,但是无论我怎么看,逻辑都和我的一样:

static int countingValleys(int n, String s) {
    int v = 0;     // # of valleys
    int lvl = 0;   // current level
    for(char c : s.toCharArray()){
        if(c == 'U') ++lvl;
        if(c == 'D') --lvl;

        // if we just came UP to sea level
        if(lvl == 0 && c == 'U')
            ++v;
    }
    return v;
}

那么我在这里缺少什么导致我无法工作的区别是什么? 谢谢。

【问题讨论】:

  • 在第二个例子中,他们使用的是char,所以== 是可以的。您正在使用 String's,它们是对象。这意味着您必须将它们与.equals 进行比较
  • 首先,使用String[] arr = s.toCharArray() 而不是String[] arr = s.split("");。我认为它会更有效率。其次,对于你的等级(海平面),在c=='U'时增加,然后检查c=='D'是否减少。
  • 查看这个可爱的debug 博客寻求帮助。一组简单的print 语句来跟踪程序操作会指出问题所在。

标签: java algorithm


【解决方案1】:

在java中,你需要这样做来比较字符串值:

        if("U".equals (arr[i])) {

不是这个:

        if(arr[i] == "U") {

前者将值“U”与 arr[i] 的内容进行比较。

后者检查字符串是否引用相同的内容或更准确地说是相同的对象实例。您可以将其视为它们指的是同一块内存吗?在这种情况下,答案是他们没有。

解决您问题的另一方面。

为什么会这样:

for(char c : s.toCharArray()){
        if(c == 'U') ++lvl;
        if(c == 'D') --lvl;

如果没有:

    String[] arr = s.split("");
    for(int i = 0; i<n;i++){
        if(arr[i] == "U"){

你说逻辑是一样的。嗯,也许吧,但数据类型不是。

在第一个版本中,字符串 s 被拆分为一个字符值数组。这些是原始值(即原始数据类型的值数组) - 就像数字一样(暂时忽略 autoboxing)。由于字符值是primitive types,所以arr[i] 中的 由== 运算符进行比较。因此arr[i] == 'U'(或“是 arr[i] 中的原始字符值等于字面值 'U')如果 arr[i] 恰好包含字母 'U',则结果为 true。

在第二个版本中,字符串 s 被拆分成一个字符串数组。这是 String 对象的实例数组(或更准确地说,是对实例的引用数组)。在这种情况下,== 运算符比较 引用值(您可能会将其视为指向两个字符串的指针)。在这种情况下,arr[i] 的值(即对字符串的引用)与对字符串文字“U”(或“D”)的引用进行比较。因此arr[i] == "U"(或“是 arr[i] 中的引用值等于包含“U”字符串的 String 实例所在位置的引用值)是错误的,因为这两个字符串位于内存中的不同位置。

如上所述,由于它们是 String 对象的不同实例,因此 == 测试为假(它们恰好包含相同值的事实在 Java 中是无关紧要的,因为 == 运算符不会查看内容)。因此,需要各种equalsequalsIgnoreCase 以及与 String 类关联的其他一些方法,这些方法准确地定义了您希望如何“比较”两个字符串值。冒着进一步混淆您的风险,您可以将“引用”或“指针”视为原始数据类型,因此,== 的行为是完全一致的。

如果这没有意义,那么请考虑其他对象类型。例如,考虑一个 Person 类,它可能具有姓名、出生日期和邮政编码属性。如果 Person 的两个实例碰巧具有相同的名称、DOB 和邮政编码,这是否意味着它们是同一个 Person?也许吧,但这也可能意味着他们是两个不同的人,只是碰巧有相同的名字、相同的出生日期并且碰巧住在同一个郊区。虽然不太可能,但它肯定会发生。

FWIW,== 在 Java 中的行为与 == 在“C”中的行为相同。不管是好是坏,对还是错,这是 Java 设计者为 Java 中的== 选择的行为。

值得注意的是,其他语言,例如Scala,为字符串定义 == 运算符(无论对错,无论好坏)以通过 == 运算符执行字符串值的比较。因此,理论上,如果您解决了其他语法问题,您的 arr[i] == "U" 测试将在 Scala 中运行。这一切都归结为了解各种运算符和方法实现的规则。

回到 Person 示例,假设 Person 在 Scala 中被定义为 case class。如果我们创建了两个具有相同名称、出生日期和邮政编码(例如 p1 和 p2)的 Person 实例,那么 p1 == p2 将是 true(在 Scala 中)。要执行引用比较(即 p1 和 p2 是同一对象的实例),我们需要使用 p1.eq(p2)(这将导致 false)。

希望 Scala 参考不会造成额外的混乱。如果是这样,那么只需将其视为运算符(或方法)的功能是由您正在使用的语言/库的设计者定义的,您需要了解他们的规则是什么。

在设计 Java 时,C 很流行,因此可以说,在 Java 中复制 == 的 C 类行为是一个不错的选择。随着时间的推移,越来越多的人认为 == 应该是一个值比较,因此一些语言已经这样实现了。

【讨论】:

  • 丹尼斯,这对您的问题有帮助吗?如果是这样,你能接受答案吗?只需单击答案旁边的灰色复选标记。谢谢
猜你喜欢
  • 1970-01-01
  • 2019-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-01
  • 2020-12-01
  • 1970-01-01
  • 2021-12-22
相关资源
最近更新 更多