简体   繁体   中英

Bulls & Cows in JavaScript

I have been struggling with the LeetCode 'Bulls & Cows' challenge for the last day. I am a front-end developer in the process of learning Algorithms, and am having a hard time understanding a block of logic achieved in Java and porting it over to my JavaScript solution.

The working Java Solution :

public String getHint(String secret, String guess) {
    int bulls = 0;
    int cows = 0;
    int[] numbers = new int[10];
    for (int i = 0; i<secret.length(); i++) {
        int s = Character.getNumericValue(secret.charAt(i));
        int g = Character.getNumericValue(guess.charAt(i));
        if (s == g) bulls++;
        else {
            if (numbers[s] < 0) cows++;
            if (numbers[g] > 0) cows++;
            numbers[s] ++;
            numbers[g] --;
        }
    }
    return bulls + "A" + cows + "B";
}

Specifically I am having a difficult time understanding the following block of functionality:

else {
    if (numbers[s] < 0) cows++;
    if (numbers[g] > 0) cows++;
    numbers[s] ++;
    numbers[g] --;
}

Here is my JS solution I have derived that is passing all (known) test cases except for secret = 1807 and guess = 7810 :

var getHint = function(secret, guess) {
  var bulls = 0;
  var cows = 0;
  var nums = [];
  var checkNums = function(num) {
    if(nums.length) {
      for (var l = 0; l < nums.length; l++) {
        if(num === nums[l]) {
          return false;
        } else {
          nums.push(num);
          cows++;

          return true;
        }
      } else {
        // /nums/ is equal to 0
        cows++;
        nums.push(num);
      }
    }
  };

  if(guess) {
    // iterate over the secret to compare it to the guess
    for (var i = 0; i < secret.length; i++) {
      // compare the related location to check for bulls
      if(secret[i] === guess[i]) {
        bulls++;
        nums.push(guess[i]);
      } else {
        // We didnt find a bull, lets check the /guess/ for cows
        for(var j = 0; j < guess.length; j++) {
          // We have a match, what should we do with it?
          if (secret[i] === guess[j]) {

              checkNums(guess[j]);

          }
        }
      }
    }
  }

  return bulls + "A" + cows + "B";
};

The failed test case I get is:

Input:
"1807"
"7810"

Output:
"1A2B"

Expected:
"1A3B"

I would love to better understand how I can replicate the elegant Java solution better, as well as any ways I can make this JS solution more succinct (and working). The more I bang my head against this, the more for loops and if blocks I wind up writing and I just know I am moving in the wrong direction.

Here is a JSBin of my solution:

http://jsbin.com/jibusa/edit?js,console

Thank you for any help.

Here is a virtual copy of the Java solution. The little adjustment to the JavaScript charCodeAt() was to account for its discrepancy with the Java Character.getNumericValue .

function getHint(secret, guess) {
  var bulls = 0;
  var cows = 0;
  var numbers = new Array(10);
  for (var i=0; i<10; i++){
    numbers[i] = 0;
  }
  for (var i = 0; i<secret.length; i++) {
    var s = secret.charCodeAt(i) - 48;
    var g = guess.charCodeAt(i) - 48;
    if (s == g) bulls++;
    else {
      if (numbers[s] < 0) cows++;
      if (numbers[g] > 0) cows++;
      numbers[s] ++;
      numbers[g] --;
    }
  }
  return bulls + "A" + cows + "B";
}

console.log(getHint("1807","7810"));

numbers[x] represents the number of unmatched x s in the prefixes of the secret and the guess scanned so far. Positive numbers indicate a surplus in the secret. Negative numbers indicate a surplus in the guess.

The code block

if (numbers[s] < 0) cows++;
if (numbers[g] > 0) cows++;
numbers[s] ++;
numbers[g] --;

translates to English as follows. If s , the current letter in the secret, has a surplus in the guess, then it matches a previous letter in the guess, so increment the number of cows. If g , the current letter in the guess, has a surplus in the secret, then it matches a previous letter in the secret, so increment the number of cows. numbers[s] ++ is very slick: it either erases a surplus letter in the guess or creates a surplus in the secret. Similarly, numbers[g] -- either erases a surplus letter in the secret or creates one in the guess.

Why don't you do this?...

  var getHint = function(secret, guess) {
  var bulls = 0;
  var cows = 0;
  var nums = [];
  var length = 10;
  var s;
  var g;
  for (var i2=0; i2 < length; i2++) {nums[i2] = 0;}
  for (var i=0; i < secret.length; i++) {
    s = Number(String(secret).charAt(i));
    g = Number(String(guess).charAt(i));

    if(s == g)bulls++;
    else{
      if(nums[s] < 0)cows++;
      if(nums[g] > 0) cows++;
      nums[s]++;
      nums[g]--;

    }
  }
  return bulls + "A" + cows + "B";
};

console.log(getHint("1123", "0111"));
console.log(getHint("1807", "7810"));

Ouput:

"1A1B"
"1A3B"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM