Expressing positive integers as the sum of different charming numbers











up vote
3
down vote

favorite












In a practice academic interview of mine, we discussed question six, round one, of the United Kingdom Mathematics Trust's 2015 British Mathematical Olympiad. Which states:




A positive integer is called charming if it is equal to 2 or is of the form
3i5j where i and j are non-negative integers. Prove that every positive integer can be written as a sum of different charming integers.




Having been able to successfully prove this, afterwards I then went on to implement, in Python, a program which can express any positive integer in terms of the sum of different charming numbers.



To do this I start by converting the integer into base 3 so that it is easier to find a charming number that is more than half the value of the original integer, but less than it. This value is then appended to a list, and the process is then repeated with the difference until left with either 1, 2, or 3. A list of charming numbers is then returned, which all sum to the original number.



I know this method works, simply as I used it somewhat in my proof.



I apologise in advance for the lack of comments.



def to_base_3(base_10: int) -> str:
working_number = int(base_10)
output = ''

while True:
next_digit = working_number % 3
output = str(next_digit) + output
working_number = working_number // 3

if working_number == 0:
return output


def to_base_10(base_3: str) -> int:
output = 0

for i, char in enumerate(base_3[::-1]):
output += int(char) * (3 ** i)

return output


def find_charming_components(number: int, charming_components: list = None) -> list:
if charming_components is None:
charming_components =

base_3_value = to_base_3(number)
digit = base_3_value[0]
component = 0

if len(base_3_value) == 1:
if digit != '0':
charming_components.append(int(digit))

return charming_components

if digit == '1':
component = to_base_10('1' + '0' * (len(base_3_value) - 1))
# Find the largest power of three that is lower than the current value. I.e: 3**4
charming_components.append(component)
# Append this charming number to the list of components

elif digit == '2':
component = to_base_10('12' + '0' * (len(base_3_value) - 2))
# Find the largest power of three times five that is lower than the current value. I.e: 3**4 * 5
charming_components.append(component)
# Append this charming number to the list of components

number -= component
# Repeat process with the difference
return find_charming_components(number, charming_components)


print(find_charming_components(int(input('Number: '))))


I just feel like doing a full base 3 conversion and back again isn't the most efficient method of doing this, and would appreciate some help on generally improving the algorithm.










share|improve this question




























    up vote
    3
    down vote

    favorite












    In a practice academic interview of mine, we discussed question six, round one, of the United Kingdom Mathematics Trust's 2015 British Mathematical Olympiad. Which states:




    A positive integer is called charming if it is equal to 2 or is of the form
    3i5j where i and j are non-negative integers. Prove that every positive integer can be written as a sum of different charming integers.




    Having been able to successfully prove this, afterwards I then went on to implement, in Python, a program which can express any positive integer in terms of the sum of different charming numbers.



    To do this I start by converting the integer into base 3 so that it is easier to find a charming number that is more than half the value of the original integer, but less than it. This value is then appended to a list, and the process is then repeated with the difference until left with either 1, 2, or 3. A list of charming numbers is then returned, which all sum to the original number.



    I know this method works, simply as I used it somewhat in my proof.



    I apologise in advance for the lack of comments.



    def to_base_3(base_10: int) -> str:
    working_number = int(base_10)
    output = ''

    while True:
    next_digit = working_number % 3
    output = str(next_digit) + output
    working_number = working_number // 3

    if working_number == 0:
    return output


    def to_base_10(base_3: str) -> int:
    output = 0

    for i, char in enumerate(base_3[::-1]):
    output += int(char) * (3 ** i)

    return output


    def find_charming_components(number: int, charming_components: list = None) -> list:
    if charming_components is None:
    charming_components =

    base_3_value = to_base_3(number)
    digit = base_3_value[0]
    component = 0

    if len(base_3_value) == 1:
    if digit != '0':
    charming_components.append(int(digit))

    return charming_components

    if digit == '1':
    component = to_base_10('1' + '0' * (len(base_3_value) - 1))
    # Find the largest power of three that is lower than the current value. I.e: 3**4
    charming_components.append(component)
    # Append this charming number to the list of components

    elif digit == '2':
    component = to_base_10('12' + '0' * (len(base_3_value) - 2))
    # Find the largest power of three times five that is lower than the current value. I.e: 3**4 * 5
    charming_components.append(component)
    # Append this charming number to the list of components

    number -= component
    # Repeat process with the difference
    return find_charming_components(number, charming_components)


    print(find_charming_components(int(input('Number: '))))


    I just feel like doing a full base 3 conversion and back again isn't the most efficient method of doing this, and would appreciate some help on generally improving the algorithm.










    share|improve this question


























      up vote
      3
      down vote

      favorite









      up vote
      3
      down vote

      favorite











      In a practice academic interview of mine, we discussed question six, round one, of the United Kingdom Mathematics Trust's 2015 British Mathematical Olympiad. Which states:




      A positive integer is called charming if it is equal to 2 or is of the form
      3i5j where i and j are non-negative integers. Prove that every positive integer can be written as a sum of different charming integers.




      Having been able to successfully prove this, afterwards I then went on to implement, in Python, a program which can express any positive integer in terms of the sum of different charming numbers.



      To do this I start by converting the integer into base 3 so that it is easier to find a charming number that is more than half the value of the original integer, but less than it. This value is then appended to a list, and the process is then repeated with the difference until left with either 1, 2, or 3. A list of charming numbers is then returned, which all sum to the original number.



      I know this method works, simply as I used it somewhat in my proof.



      I apologise in advance for the lack of comments.



      def to_base_3(base_10: int) -> str:
      working_number = int(base_10)
      output = ''

      while True:
      next_digit = working_number % 3
      output = str(next_digit) + output
      working_number = working_number // 3

      if working_number == 0:
      return output


      def to_base_10(base_3: str) -> int:
      output = 0

      for i, char in enumerate(base_3[::-1]):
      output += int(char) * (3 ** i)

      return output


      def find_charming_components(number: int, charming_components: list = None) -> list:
      if charming_components is None:
      charming_components =

      base_3_value = to_base_3(number)
      digit = base_3_value[0]
      component = 0

      if len(base_3_value) == 1:
      if digit != '0':
      charming_components.append(int(digit))

      return charming_components

      if digit == '1':
      component = to_base_10('1' + '0' * (len(base_3_value) - 1))
      # Find the largest power of three that is lower than the current value. I.e: 3**4
      charming_components.append(component)
      # Append this charming number to the list of components

      elif digit == '2':
      component = to_base_10('12' + '0' * (len(base_3_value) - 2))
      # Find the largest power of three times five that is lower than the current value. I.e: 3**4 * 5
      charming_components.append(component)
      # Append this charming number to the list of components

      number -= component
      # Repeat process with the difference
      return find_charming_components(number, charming_components)


      print(find_charming_components(int(input('Number: '))))


      I just feel like doing a full base 3 conversion and back again isn't the most efficient method of doing this, and would appreciate some help on generally improving the algorithm.










      share|improve this question















      In a practice academic interview of mine, we discussed question six, round one, of the United Kingdom Mathematics Trust's 2015 British Mathematical Olympiad. Which states:




      A positive integer is called charming if it is equal to 2 or is of the form
      3i5j where i and j are non-negative integers. Prove that every positive integer can be written as a sum of different charming integers.




      Having been able to successfully prove this, afterwards I then went on to implement, in Python, a program which can express any positive integer in terms of the sum of different charming numbers.



      To do this I start by converting the integer into base 3 so that it is easier to find a charming number that is more than half the value of the original integer, but less than it. This value is then appended to a list, and the process is then repeated with the difference until left with either 1, 2, or 3. A list of charming numbers is then returned, which all sum to the original number.



      I know this method works, simply as I used it somewhat in my proof.



      I apologise in advance for the lack of comments.



      def to_base_3(base_10: int) -> str:
      working_number = int(base_10)
      output = ''

      while True:
      next_digit = working_number % 3
      output = str(next_digit) + output
      working_number = working_number // 3

      if working_number == 0:
      return output


      def to_base_10(base_3: str) -> int:
      output = 0

      for i, char in enumerate(base_3[::-1]):
      output += int(char) * (3 ** i)

      return output


      def find_charming_components(number: int, charming_components: list = None) -> list:
      if charming_components is None:
      charming_components =

      base_3_value = to_base_3(number)
      digit = base_3_value[0]
      component = 0

      if len(base_3_value) == 1:
      if digit != '0':
      charming_components.append(int(digit))

      return charming_components

      if digit == '1':
      component = to_base_10('1' + '0' * (len(base_3_value) - 1))
      # Find the largest power of three that is lower than the current value. I.e: 3**4
      charming_components.append(component)
      # Append this charming number to the list of components

      elif digit == '2':
      component = to_base_10('12' + '0' * (len(base_3_value) - 2))
      # Find the largest power of three times five that is lower than the current value. I.e: 3**4 * 5
      charming_components.append(component)
      # Append this charming number to the list of components

      number -= component
      # Repeat process with the difference
      return find_charming_components(number, charming_components)


      print(find_charming_components(int(input('Number: '))))


      I just feel like doing a full base 3 conversion and back again isn't the most efficient method of doing this, and would appreciate some help on generally improving the algorithm.







      python python-3.x interview-questions mathematics integer






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 27 at 4:10









      200_success

      127k15149412




      127k15149412










      asked Nov 26 at 23:29









      George Willcox

      379117




      379117






















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          3
          down vote













          Your to_base_10(x) function may be easily rewritten as:



          def to_base_10(base_3):
          return int(base_3, 3)


          However, you are only using the function to convert base 3 numbers of the forms '1' followed by n zeros, and '12' followed by n zeros. These can be directly computed as:





          • to_base_10('1' + '0'*n) --> 3 ** n


          • to_base_10('12' + '0'*n) --> 5 * 3**n




          The output of the to_base_3(x) function is only used to produce 2 values: len(base_3_value) and digit = base_3_value[0]. These can also be directly computed.



          if number > 0:
          len_base_3_value = int(math.log(number, 3)) + 1
          digit = number // (3 ** (len_base_3_value - 1))
          else:
          len_base_3_value = 1
          digit = 0


          Note: digit is now an int (0, 1, or 2), not a str ('0', '1', or '2')





          You recursively call and then return the value of find_charming_components(number, charming_components). Python does not do tail recursion optimization, so this should be replaced with a simple loop, instead of recursion.






          share|improve this answer






























            up vote
            1
            down vote














            def to_base_3(base_10: int) -> str:



            Why str? I think it's simpler to use lists of digits.



            base_10 is a misleading name. It's an integer. It's actually in base 2 in just about every CPU this code will ever be run on.






            def to_base_10(base_3: str) -> int:



            Similarly: this is from_base_3 to integer.




                output = 0

            for i, char in enumerate(base_3[::-1]):
            output += int(char) * (3 ** i)

            return output



            It's simpler to convert from a list of digits to an integer in big-endian order:



            def to_base_10(base_3: str) -> int:
            output = 0

            for char in base_3:
            output = 3 * output + int(char)

            return output





            def find_charming_components(number: int, charming_components: list = None) -> list:
            if charming_components is None:
            charming_components =



            Frankly this is ugly. I understand that you want to use append for efficiency, but it would be cleaner with an inner recursive method.






                if digit == '1':
            component = to_base_10('1' + '0' * (len(base_3_value) - 1))
            # Find the largest power of three that is lower than the current value. I.e: 3**4
            charming_components.append(component)
            # Append this charming number to the list of components



            I don't think I've ever seen comments after the code before, and it took me a while to work out what was going on.



            If you have closed form expressions, why call to_base_10?



            Also, surely it's "no greater than" rather than "lower than"?




                elif digit == '2':



            Why not just else:?




                    charming_components.append(component)



            If the same code ends all the cases, it can be pulled out.





            At this point I have



            def find_charming_components(number: int) -> list:
            charming_components =

            def helper(n):
            base_3_value = to_base_3(n)
            digit = base_3_value[0]

            if len(base_3_value) == 1:
            if digit != 0:
            charming_components.append(digit)
            return

            component = 0
            if digit == 1:
            # Find the largest power of three that is no greater than the current value. E.g: 3**4
            component = 3 ** (len(base_3_value) - 1)
            else:
            # Find the largest power of three times five that is no greater than the current value. E.g: 3**4 * 5
            component = 5 * 3 ** (len(base_3_value) - 2)

            charming_components.append(component)
            # Repeat process with the difference
            helper(n - component)

            helper(number)
            return charming_components


            Now, helper is clearly tail-recursive, so is easy to replace with a loop:



            def find_charming_components(number: int) -> list:
            charming_components =

            while number > 0:
            base_3_value = to_base_3(number)
            digit = base_3_value[0]

            if len(base_3_value) == 1:
            if digit != 0:
            charming_components.append(digit)
            break

            component = 0
            if digit == 1:
            # Find the largest power of three that is lower than the current value. E.g: 3**4
            component = 3 ** (len(base_3_value) - 1)
            else:
            # Find the largest power of three times five that is lower than the current value. E.g: 3**4 * 5
            component = 5 * 3 ** (len(base_3_value) - 2)

            charming_components.append(component)
            # Repeat process with the difference
            number -= component

            return charming_components




            At this point, the remaining issue is the cost of the conversion to base 3. Observing the sequence of numbers, we can easily generate them and then filter:



            def find_charming_components(number: int) -> list:
            candidates = [1, 2, 3]
            current = 3
            while current < number:
            candidates.extend([current // 3 * 5, current * 3])
            current *= 3

            charming_components =
            for candidate in reversed(candidates):
            if number >= candidate:
            charming_components.append(candidate)
            number -= candidate

            return charming_components





            share|improve this answer





















              Your Answer





              StackExchange.ifUsing("editor", function () {
              return StackExchange.using("mathjaxEditing", function () {
              StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
              StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
              });
              });
              }, "mathjax-editing");

              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "196"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              convertImagesToLinks: false,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: null,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208489%2fexpressing-positive-integers-as-the-sum-of-different-charming-numbers%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes








              up vote
              3
              down vote













              Your to_base_10(x) function may be easily rewritten as:



              def to_base_10(base_3):
              return int(base_3, 3)


              However, you are only using the function to convert base 3 numbers of the forms '1' followed by n zeros, and '12' followed by n zeros. These can be directly computed as:





              • to_base_10('1' + '0'*n) --> 3 ** n


              • to_base_10('12' + '0'*n) --> 5 * 3**n




              The output of the to_base_3(x) function is only used to produce 2 values: len(base_3_value) and digit = base_3_value[0]. These can also be directly computed.



              if number > 0:
              len_base_3_value = int(math.log(number, 3)) + 1
              digit = number // (3 ** (len_base_3_value - 1))
              else:
              len_base_3_value = 1
              digit = 0


              Note: digit is now an int (0, 1, or 2), not a str ('0', '1', or '2')





              You recursively call and then return the value of find_charming_components(number, charming_components). Python does not do tail recursion optimization, so this should be replaced with a simple loop, instead of recursion.






              share|improve this answer



























                up vote
                3
                down vote













                Your to_base_10(x) function may be easily rewritten as:



                def to_base_10(base_3):
                return int(base_3, 3)


                However, you are only using the function to convert base 3 numbers of the forms '1' followed by n zeros, and '12' followed by n zeros. These can be directly computed as:





                • to_base_10('1' + '0'*n) --> 3 ** n


                • to_base_10('12' + '0'*n) --> 5 * 3**n




                The output of the to_base_3(x) function is only used to produce 2 values: len(base_3_value) and digit = base_3_value[0]. These can also be directly computed.



                if number > 0:
                len_base_3_value = int(math.log(number, 3)) + 1
                digit = number // (3 ** (len_base_3_value - 1))
                else:
                len_base_3_value = 1
                digit = 0


                Note: digit is now an int (0, 1, or 2), not a str ('0', '1', or '2')





                You recursively call and then return the value of find_charming_components(number, charming_components). Python does not do tail recursion optimization, so this should be replaced with a simple loop, instead of recursion.






                share|improve this answer

























                  up vote
                  3
                  down vote










                  up vote
                  3
                  down vote









                  Your to_base_10(x) function may be easily rewritten as:



                  def to_base_10(base_3):
                  return int(base_3, 3)


                  However, you are only using the function to convert base 3 numbers of the forms '1' followed by n zeros, and '12' followed by n zeros. These can be directly computed as:





                  • to_base_10('1' + '0'*n) --> 3 ** n


                  • to_base_10('12' + '0'*n) --> 5 * 3**n




                  The output of the to_base_3(x) function is only used to produce 2 values: len(base_3_value) and digit = base_3_value[0]. These can also be directly computed.



                  if number > 0:
                  len_base_3_value = int(math.log(number, 3)) + 1
                  digit = number // (3 ** (len_base_3_value - 1))
                  else:
                  len_base_3_value = 1
                  digit = 0


                  Note: digit is now an int (0, 1, or 2), not a str ('0', '1', or '2')





                  You recursively call and then return the value of find_charming_components(number, charming_components). Python does not do tail recursion optimization, so this should be replaced with a simple loop, instead of recursion.






                  share|improve this answer














                  Your to_base_10(x) function may be easily rewritten as:



                  def to_base_10(base_3):
                  return int(base_3, 3)


                  However, you are only using the function to convert base 3 numbers of the forms '1' followed by n zeros, and '12' followed by n zeros. These can be directly computed as:





                  • to_base_10('1' + '0'*n) --> 3 ** n


                  • to_base_10('12' + '0'*n) --> 5 * 3**n




                  The output of the to_base_3(x) function is only used to produce 2 values: len(base_3_value) and digit = base_3_value[0]. These can also be directly computed.



                  if number > 0:
                  len_base_3_value = int(math.log(number, 3)) + 1
                  digit = number // (3 ** (len_base_3_value - 1))
                  else:
                  len_base_3_value = 1
                  digit = 0


                  Note: digit is now an int (0, 1, or 2), not a str ('0', '1', or '2')





                  You recursively call and then return the value of find_charming_components(number, charming_components). Python does not do tail recursion optimization, so this should be replaced with a simple loop, instead of recursion.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 27 at 14:22

























                  answered Nov 27 at 2:14









                  AJNeufeld

                  3,814317




                  3,814317
























                      up vote
                      1
                      down vote














                      def to_base_3(base_10: int) -> str:



                      Why str? I think it's simpler to use lists of digits.



                      base_10 is a misleading name. It's an integer. It's actually in base 2 in just about every CPU this code will ever be run on.






                      def to_base_10(base_3: str) -> int:



                      Similarly: this is from_base_3 to integer.




                          output = 0

                      for i, char in enumerate(base_3[::-1]):
                      output += int(char) * (3 ** i)

                      return output



                      It's simpler to convert from a list of digits to an integer in big-endian order:



                      def to_base_10(base_3: str) -> int:
                      output = 0

                      for char in base_3:
                      output = 3 * output + int(char)

                      return output





                      def find_charming_components(number: int, charming_components: list = None) -> list:
                      if charming_components is None:
                      charming_components =



                      Frankly this is ugly. I understand that you want to use append for efficiency, but it would be cleaner with an inner recursive method.






                          if digit == '1':
                      component = to_base_10('1' + '0' * (len(base_3_value) - 1))
                      # Find the largest power of three that is lower than the current value. I.e: 3**4
                      charming_components.append(component)
                      # Append this charming number to the list of components



                      I don't think I've ever seen comments after the code before, and it took me a while to work out what was going on.



                      If you have closed form expressions, why call to_base_10?



                      Also, surely it's "no greater than" rather than "lower than"?




                          elif digit == '2':



                      Why not just else:?




                              charming_components.append(component)



                      If the same code ends all the cases, it can be pulled out.





                      At this point I have



                      def find_charming_components(number: int) -> list:
                      charming_components =

                      def helper(n):
                      base_3_value = to_base_3(n)
                      digit = base_3_value[0]

                      if len(base_3_value) == 1:
                      if digit != 0:
                      charming_components.append(digit)
                      return

                      component = 0
                      if digit == 1:
                      # Find the largest power of three that is no greater than the current value. E.g: 3**4
                      component = 3 ** (len(base_3_value) - 1)
                      else:
                      # Find the largest power of three times five that is no greater than the current value. E.g: 3**4 * 5
                      component = 5 * 3 ** (len(base_3_value) - 2)

                      charming_components.append(component)
                      # Repeat process with the difference
                      helper(n - component)

                      helper(number)
                      return charming_components


                      Now, helper is clearly tail-recursive, so is easy to replace with a loop:



                      def find_charming_components(number: int) -> list:
                      charming_components =

                      while number > 0:
                      base_3_value = to_base_3(number)
                      digit = base_3_value[0]

                      if len(base_3_value) == 1:
                      if digit != 0:
                      charming_components.append(digit)
                      break

                      component = 0
                      if digit == 1:
                      # Find the largest power of three that is lower than the current value. E.g: 3**4
                      component = 3 ** (len(base_3_value) - 1)
                      else:
                      # Find the largest power of three times five that is lower than the current value. E.g: 3**4 * 5
                      component = 5 * 3 ** (len(base_3_value) - 2)

                      charming_components.append(component)
                      # Repeat process with the difference
                      number -= component

                      return charming_components




                      At this point, the remaining issue is the cost of the conversion to base 3. Observing the sequence of numbers, we can easily generate them and then filter:



                      def find_charming_components(number: int) -> list:
                      candidates = [1, 2, 3]
                      current = 3
                      while current < number:
                      candidates.extend([current // 3 * 5, current * 3])
                      current *= 3

                      charming_components =
                      for candidate in reversed(candidates):
                      if number >= candidate:
                      charming_components.append(candidate)
                      number -= candidate

                      return charming_components





                      share|improve this answer

























                        up vote
                        1
                        down vote














                        def to_base_3(base_10: int) -> str:



                        Why str? I think it's simpler to use lists of digits.



                        base_10 is a misleading name. It's an integer. It's actually in base 2 in just about every CPU this code will ever be run on.






                        def to_base_10(base_3: str) -> int:



                        Similarly: this is from_base_3 to integer.




                            output = 0

                        for i, char in enumerate(base_3[::-1]):
                        output += int(char) * (3 ** i)

                        return output



                        It's simpler to convert from a list of digits to an integer in big-endian order:



                        def to_base_10(base_3: str) -> int:
                        output = 0

                        for char in base_3:
                        output = 3 * output + int(char)

                        return output





                        def find_charming_components(number: int, charming_components: list = None) -> list:
                        if charming_components is None:
                        charming_components =



                        Frankly this is ugly. I understand that you want to use append for efficiency, but it would be cleaner with an inner recursive method.






                            if digit == '1':
                        component = to_base_10('1' + '0' * (len(base_3_value) - 1))
                        # Find the largest power of three that is lower than the current value. I.e: 3**4
                        charming_components.append(component)
                        # Append this charming number to the list of components



                        I don't think I've ever seen comments after the code before, and it took me a while to work out what was going on.



                        If you have closed form expressions, why call to_base_10?



                        Also, surely it's "no greater than" rather than "lower than"?




                            elif digit == '2':



                        Why not just else:?




                                charming_components.append(component)



                        If the same code ends all the cases, it can be pulled out.





                        At this point I have



                        def find_charming_components(number: int) -> list:
                        charming_components =

                        def helper(n):
                        base_3_value = to_base_3(n)
                        digit = base_3_value[0]

                        if len(base_3_value) == 1:
                        if digit != 0:
                        charming_components.append(digit)
                        return

                        component = 0
                        if digit == 1:
                        # Find the largest power of three that is no greater than the current value. E.g: 3**4
                        component = 3 ** (len(base_3_value) - 1)
                        else:
                        # Find the largest power of three times five that is no greater than the current value. E.g: 3**4 * 5
                        component = 5 * 3 ** (len(base_3_value) - 2)

                        charming_components.append(component)
                        # Repeat process with the difference
                        helper(n - component)

                        helper(number)
                        return charming_components


                        Now, helper is clearly tail-recursive, so is easy to replace with a loop:



                        def find_charming_components(number: int) -> list:
                        charming_components =

                        while number > 0:
                        base_3_value = to_base_3(number)
                        digit = base_3_value[0]

                        if len(base_3_value) == 1:
                        if digit != 0:
                        charming_components.append(digit)
                        break

                        component = 0
                        if digit == 1:
                        # Find the largest power of three that is lower than the current value. E.g: 3**4
                        component = 3 ** (len(base_3_value) - 1)
                        else:
                        # Find the largest power of three times five that is lower than the current value. E.g: 3**4 * 5
                        component = 5 * 3 ** (len(base_3_value) - 2)

                        charming_components.append(component)
                        # Repeat process with the difference
                        number -= component

                        return charming_components




                        At this point, the remaining issue is the cost of the conversion to base 3. Observing the sequence of numbers, we can easily generate them and then filter:



                        def find_charming_components(number: int) -> list:
                        candidates = [1, 2, 3]
                        current = 3
                        while current < number:
                        candidates.extend([current // 3 * 5, current * 3])
                        current *= 3

                        charming_components =
                        for candidate in reversed(candidates):
                        if number >= candidate:
                        charming_components.append(candidate)
                        number -= candidate

                        return charming_components





                        share|improve this answer























                          up vote
                          1
                          down vote










                          up vote
                          1
                          down vote










                          def to_base_3(base_10: int) -> str:



                          Why str? I think it's simpler to use lists of digits.



                          base_10 is a misleading name. It's an integer. It's actually in base 2 in just about every CPU this code will ever be run on.






                          def to_base_10(base_3: str) -> int:



                          Similarly: this is from_base_3 to integer.




                              output = 0

                          for i, char in enumerate(base_3[::-1]):
                          output += int(char) * (3 ** i)

                          return output



                          It's simpler to convert from a list of digits to an integer in big-endian order:



                          def to_base_10(base_3: str) -> int:
                          output = 0

                          for char in base_3:
                          output = 3 * output + int(char)

                          return output





                          def find_charming_components(number: int, charming_components: list = None) -> list:
                          if charming_components is None:
                          charming_components =



                          Frankly this is ugly. I understand that you want to use append for efficiency, but it would be cleaner with an inner recursive method.






                              if digit == '1':
                          component = to_base_10('1' + '0' * (len(base_3_value) - 1))
                          # Find the largest power of three that is lower than the current value. I.e: 3**4
                          charming_components.append(component)
                          # Append this charming number to the list of components



                          I don't think I've ever seen comments after the code before, and it took me a while to work out what was going on.



                          If you have closed form expressions, why call to_base_10?



                          Also, surely it's "no greater than" rather than "lower than"?




                              elif digit == '2':



                          Why not just else:?




                                  charming_components.append(component)



                          If the same code ends all the cases, it can be pulled out.





                          At this point I have



                          def find_charming_components(number: int) -> list:
                          charming_components =

                          def helper(n):
                          base_3_value = to_base_3(n)
                          digit = base_3_value[0]

                          if len(base_3_value) == 1:
                          if digit != 0:
                          charming_components.append(digit)
                          return

                          component = 0
                          if digit == 1:
                          # Find the largest power of three that is no greater than the current value. E.g: 3**4
                          component = 3 ** (len(base_3_value) - 1)
                          else:
                          # Find the largest power of three times five that is no greater than the current value. E.g: 3**4 * 5
                          component = 5 * 3 ** (len(base_3_value) - 2)

                          charming_components.append(component)
                          # Repeat process with the difference
                          helper(n - component)

                          helper(number)
                          return charming_components


                          Now, helper is clearly tail-recursive, so is easy to replace with a loop:



                          def find_charming_components(number: int) -> list:
                          charming_components =

                          while number > 0:
                          base_3_value = to_base_3(number)
                          digit = base_3_value[0]

                          if len(base_3_value) == 1:
                          if digit != 0:
                          charming_components.append(digit)
                          break

                          component = 0
                          if digit == 1:
                          # Find the largest power of three that is lower than the current value. E.g: 3**4
                          component = 3 ** (len(base_3_value) - 1)
                          else:
                          # Find the largest power of three times five that is lower than the current value. E.g: 3**4 * 5
                          component = 5 * 3 ** (len(base_3_value) - 2)

                          charming_components.append(component)
                          # Repeat process with the difference
                          number -= component

                          return charming_components




                          At this point, the remaining issue is the cost of the conversion to base 3. Observing the sequence of numbers, we can easily generate them and then filter:



                          def find_charming_components(number: int) -> list:
                          candidates = [1, 2, 3]
                          current = 3
                          while current < number:
                          candidates.extend([current // 3 * 5, current * 3])
                          current *= 3

                          charming_components =
                          for candidate in reversed(candidates):
                          if number >= candidate:
                          charming_components.append(candidate)
                          number -= candidate

                          return charming_components





                          share|improve this answer













                          def to_base_3(base_10: int) -> str:



                          Why str? I think it's simpler to use lists of digits.



                          base_10 is a misleading name. It's an integer. It's actually in base 2 in just about every CPU this code will ever be run on.






                          def to_base_10(base_3: str) -> int:



                          Similarly: this is from_base_3 to integer.




                              output = 0

                          for i, char in enumerate(base_3[::-1]):
                          output += int(char) * (3 ** i)

                          return output



                          It's simpler to convert from a list of digits to an integer in big-endian order:



                          def to_base_10(base_3: str) -> int:
                          output = 0

                          for char in base_3:
                          output = 3 * output + int(char)

                          return output





                          def find_charming_components(number: int, charming_components: list = None) -> list:
                          if charming_components is None:
                          charming_components =



                          Frankly this is ugly. I understand that you want to use append for efficiency, but it would be cleaner with an inner recursive method.






                              if digit == '1':
                          component = to_base_10('1' + '0' * (len(base_3_value) - 1))
                          # Find the largest power of three that is lower than the current value. I.e: 3**4
                          charming_components.append(component)
                          # Append this charming number to the list of components



                          I don't think I've ever seen comments after the code before, and it took me a while to work out what was going on.



                          If you have closed form expressions, why call to_base_10?



                          Also, surely it's "no greater than" rather than "lower than"?




                              elif digit == '2':



                          Why not just else:?




                                  charming_components.append(component)



                          If the same code ends all the cases, it can be pulled out.





                          At this point I have



                          def find_charming_components(number: int) -> list:
                          charming_components =

                          def helper(n):
                          base_3_value = to_base_3(n)
                          digit = base_3_value[0]

                          if len(base_3_value) == 1:
                          if digit != 0:
                          charming_components.append(digit)
                          return

                          component = 0
                          if digit == 1:
                          # Find the largest power of three that is no greater than the current value. E.g: 3**4
                          component = 3 ** (len(base_3_value) - 1)
                          else:
                          # Find the largest power of three times five that is no greater than the current value. E.g: 3**4 * 5
                          component = 5 * 3 ** (len(base_3_value) - 2)

                          charming_components.append(component)
                          # Repeat process with the difference
                          helper(n - component)

                          helper(number)
                          return charming_components


                          Now, helper is clearly tail-recursive, so is easy to replace with a loop:



                          def find_charming_components(number: int) -> list:
                          charming_components =

                          while number > 0:
                          base_3_value = to_base_3(number)
                          digit = base_3_value[0]

                          if len(base_3_value) == 1:
                          if digit != 0:
                          charming_components.append(digit)
                          break

                          component = 0
                          if digit == 1:
                          # Find the largest power of three that is lower than the current value. E.g: 3**4
                          component = 3 ** (len(base_3_value) - 1)
                          else:
                          # Find the largest power of three times five that is lower than the current value. E.g: 3**4 * 5
                          component = 5 * 3 ** (len(base_3_value) - 2)

                          charming_components.append(component)
                          # Repeat process with the difference
                          number -= component

                          return charming_components




                          At this point, the remaining issue is the cost of the conversion to base 3. Observing the sequence of numbers, we can easily generate them and then filter:



                          def find_charming_components(number: int) -> list:
                          candidates = [1, 2, 3]
                          current = 3
                          while current < number:
                          candidates.extend([current // 3 * 5, current * 3])
                          current *= 3

                          charming_components =
                          for candidate in reversed(candidates):
                          if number >= candidate:
                          charming_components.append(candidate)
                          number -= candidate

                          return charming_components






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Nov 27 at 15:42









                          Peter Taylor

                          15.4k2657




                          15.4k2657






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Code Review Stack Exchange!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              Use MathJax to format equations. MathJax reference.


                              To learn more, see our tips on writing great answers.





                              Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                              Please pay close attention to the following guidance:


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208489%2fexpressing-positive-integers-as-the-sum-of-different-charming-numbers%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              Список кардиналов, возведённых папой римским Каликстом III

                              Deduzione

                              Mysql.sock missing - “Can't connect to local MySQL server through socket”