Find the Punishment Number of an Integer

medium math backtracking partition

Problem

Given a positive integer n, return its punishment number: the sum of i*i over every integer i with 1 ≤ i ≤ n such that the decimal digits of i*i can be split into contiguous substrings whose integer values add up to exactly i.

Inputn = 10
Output182
i = 1 (1=1), i = 9 (81 → 8+1 = 9), and i = 10 (100 → 10+0 = 10) qualify. So 1 + 81 + 100 = 182.

def punishmentNumber(n):
    # Can digits of s[start:] be split so the parts sum to target?
    def can(s, start, target):
        if start == len(s):
            return target == 0        # used all digits, hit target exactly
        cur = 0
        for end in range(start, len(s)):
            cur = cur * 10 + int(s[end])   # extend current substring
            if cur > target:
                break                 # too big, and only grows -> prune
            if can(s, end + 1, target - cur):
                return True            # this cut works
        return False

    total = 0
    for i in range(1, n + 1):
        if can(str(i * i), 0, i):     # square can be partitioned into i
            total += i * i
    return total
function punishmentNumber(n) {
  // Can digits of s from `start` be split so parts sum to target?
  function can(s, start, target) {
    if (start === s.length) return target === 0;
    let cur = 0;
    for (let end = start; end < s.length; end++) {
      cur = cur * 10 + (s.charCodeAt(end) - 48); // extend substring
      if (cur > target) break;                   // prune: only grows
      if (can(s, end + 1, target - cur)) return true;
    }
    return false;
  }

  let total = 0;
  for (let i = 1; i <= n; i++) {
    if (can(String(i * i), 0, i)) total += i * i;
  }
  return total;
}
int punishmentNumber(int n) {
    int total = 0;
    for (int i = 1; i <= n; i++) {
        String s = Integer.toString(i * i);
        if (can(s, 0, i)) total += i * i;
    }
    return total;
}

// Can digits of s from `start` be split so parts sum to target?
boolean can(String s, int start, int target) {
    if (start == s.length()) return target == 0;
    int cur = 0;
    for (int end = start; end < s.length(); end++) {
        cur = cur * 10 + (s.charAt(end) - '0'); // extend substring
        if (cur > target) break;                // prune: only grows
        if (can(s, end + 1, target - cur)) return true;
    }
    return false;
}
bool can(const string& s, int start, int target) {
    if (start == (int)s.size()) return target == 0;
    int cur = 0;
    for (int end = start; end < (int)s.size(); end++) {
        cur = cur * 10 + (s[end] - '0');  // extend substring
        if (cur > target) break;          // prune: only grows
        if (can(s, end + 1, target - cur)) return true;
    }
    return false;
}

int punishmentNumber(int n) {
    int total = 0;
    for (int i = 1; i <= n; i++) {
        if (can(to_string(i * i), 0, i)) total += i * i;
    }
    return total;
}
Time: O(n · 2d), d = digits of i² (≤ 7) Space: O(d) recursion depth