LeetCode 189 - Rotate Array












5














I have a working solution for this problem that was accepted in LeetCode:




Given an array, rotate the array to the right by k steps, where k is non-negative."




function rotate(nums, k) {
for (let i = 1; i <= k; i += 1) {
const poppedNum = nums.pop();
nums.unshift(poppedNum);
}

return nums;
}

// rotate([1, 2, 3, 4, 5, 6, 7], 3) -> [5, 6, 7, 1, 2, 3, 4]


Questions:




  • Would the time complexity be $O(k)$ and space complexity be $O(1)$?


  • Is there a better way to solve this? The question asked to rotate the elements in-place if possible, but I am not sure how to accomplish this at the moment.











share|improve this question









New contributor




davidatthepark is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

























    5














    I have a working solution for this problem that was accepted in LeetCode:




    Given an array, rotate the array to the right by k steps, where k is non-negative."




    function rotate(nums, k) {
    for (let i = 1; i <= k; i += 1) {
    const poppedNum = nums.pop();
    nums.unshift(poppedNum);
    }

    return nums;
    }

    // rotate([1, 2, 3, 4, 5, 6, 7], 3) -> [5, 6, 7, 1, 2, 3, 4]


    Questions:




    • Would the time complexity be $O(k)$ and space complexity be $O(1)$?


    • Is there a better way to solve this? The question asked to rotate the elements in-place if possible, but I am not sure how to accomplish this at the moment.











    share|improve this question









    New contributor




    davidatthepark is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.























      5












      5








      5







      I have a working solution for this problem that was accepted in LeetCode:




      Given an array, rotate the array to the right by k steps, where k is non-negative."




      function rotate(nums, k) {
      for (let i = 1; i <= k; i += 1) {
      const poppedNum = nums.pop();
      nums.unshift(poppedNum);
      }

      return nums;
      }

      // rotate([1, 2, 3, 4, 5, 6, 7], 3) -> [5, 6, 7, 1, 2, 3, 4]


      Questions:




      • Would the time complexity be $O(k)$ and space complexity be $O(1)$?


      • Is there a better way to solve this? The question asked to rotate the elements in-place if possible, but I am not sure how to accomplish this at the moment.











      share|improve this question









      New contributor




      davidatthepark is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      I have a working solution for this problem that was accepted in LeetCode:




      Given an array, rotate the array to the right by k steps, where k is non-negative."




      function rotate(nums, k) {
      for (let i = 1; i <= k; i += 1) {
      const poppedNum = nums.pop();
      nums.unshift(poppedNum);
      }

      return nums;
      }

      // rotate([1, 2, 3, 4, 5, 6, 7], 3) -> [5, 6, 7, 1, 2, 3, 4]


      Questions:




      • Would the time complexity be $O(k)$ and space complexity be $O(1)$?


      • Is there a better way to solve this? The question asked to rotate the elements in-place if possible, but I am not sure how to accomplish this at the moment.








      javascript algorithm interview-questions






      share|improve this question









      New contributor




      davidatthepark is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      davidatthepark is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 3 hours ago









      Jamal

      30.3k11116226




      30.3k11116226






      New contributor




      davidatthepark is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked yesterday









      davidatthepark

      1313




      1313




      New contributor




      davidatthepark is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      davidatthepark is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      davidatthepark is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          3 Answers
          3






          active

          oldest

          votes


















          3














          Review



          Not bad, but there is room for a few improvements to avoid some possible problematic input arguments.



          Style



          Some points on your code.




          • The names nums and k could be better, maybe array and rotateBy

          • Try to avoid one use variables unless it makes the lines using them to long. Thus you can pop and unshift in one line nums.unshift(nums.pop());

          • Idiomatic javascript uses zero based loop counters rather than starting at 1. Thus the loop would be for (let i = 0; i < k; i++) {


          Complexity



          Your complexity is $O(n)$ and storage $O(1)$ where $n$ is the number of rotations, the range $n>0$



          However consider the next examples



          rotate([1,2,3,4,5,6,7,8,9], 18); // Will rotate 18 times same as rotate 0
          rotate([1,2,3,4,5,6,7,8,9], 8); // Will rotate 8 times same as rotate left 1
          rotate([1], 8e9); // Will spend a lot of time not changing anything


          Your function will do too much work if the rotations are outside the expected ranges, the rotation can be done in reverse in less steps, or rotating has no effect.



          You can limit the complexity to $O(k)$ where $0<k<=n/2$



          Rewrite



          This is a slight improvement on your function to ensure you don't rotate more than needed.



          function rotate(array, rotateBy) {
          rotateBy %= array.length;
          if (rotateBy < array.length - rotateBy) {
          while (rotateBy--) { array.unshift(array.pop()) }
          } else {
          rotateBy = array.length - rotateBy;
          while (rotateBy--) { array.push(array.shift()) }
          }
          return array;
          }


          Update



          As vnp's answer points out the complexity of Array.unshift and Array.shift is not as simple as $O(1)$ and will depend on the array type. We can assume the best case for this problem, sparse array (effectively a hash table) and thus will grow/shrink down at $O(1)$



          In that case the function above has a mean complexity of $O(log(n))$ of all possible values of $k$



          Note that if the cost of grow/shrink operations is $O(n)$ (dense array) this will add $n$ operations for each $k$ making the above $O(kn)$ with $0<=k<(n/2)$ Expressed in terms of $n$ or $k$ only it remains $O(log(n))$ or $O(k)$





          You could also use Array.splice



           array.unshift(...array.splice(-rotateBy,rotateBy));


          However under the hood the complexity would be a little greater $O(2n)$ (which is still $O(n)$) as splice steps over each item to remove and add to a new array. Then ... steps over them again to unshift each item to the array.



          The storage would also increase as the spliced array is held in memory until the code has finished unshifting them making storage $O(n)$



          If the array contained all the same values the rotation would have no effect thus all rotation could be done in O(1). However there is no way to know this without checking each item in turn.






          share|improve this answer































            3














            The time complexity really depends on the unshift time complexity. ECMA does not specify it, but I would expect that it is not constant. I would not be surprised if it is actually linear in the size of the array. If so, the complexity of rotate would be $O(nk)$.



            In fact, I tested the performance of your code by timing your rotate by 1, for arrays of size from 100000 to 100000000, doubling the size every time. The results (in milliseconds) are



            1, 3, 8, 14, 29, 33, 69, 229, 447, 926


            I did few runs, the exact numbers were different, but consistent. You can see that as size doubles the run time (at least) doubles as well.



            And again, it was rotation by 1. Rotation by k will take proportionally longer.





            There are few classic algorithms which perform the rotation in true $O(n)$ complexity, that is their execution time does not depend on k. One is extremely simple to code, but takes effort to comprehend. In pseudocode:



                reverse(0, k)
            reverse(k, n)
            reverse(0, n)


            Notice that each element is moved twice. This is suboptimal. Another algorithm moves each element exactly once - right into the place where it belongs. I don't want to spoil the fun of discovering it. Try to figure it out (hint: it needs to compute gcd(n, k)).





            That said, the leetcode problem only asks to print the rotated array. I would seriously consider to not actually perform rotation, but



                print values from n-k to n
            print values from 0 to n-k


            It feels like cheating, but in fact it is valid, and sometimes very useful technique.






            share|improve this answer























            • JS has two types of arrays, sparse and dense. There is no programmatic way to determine what an arrays type is. Sparse arrays use a cheap hash to locate items and thus would not suffer from the need to memcpy all items up/down one position when calling Array.unshift or Array.shift It is generally assumed that these operations are O(1). Array memory allocations are never single items but rather double array size, or wait and half. Using this scheme does make it possible to have an array that can grow in both directions at O(1). Whether this is in fact done I do not know.
              – Blindman67
              18 hours ago



















            1














            Think twice before modifying function parameters



            The posted code modifies the content of the input array nums and also returns it.
            When a function returns something,
            it can be confusing if it also modifies the input — a side effect.
            Modifying the input and not returning anything (void in other programming languages) is not confusing.
            I think it's important to make a conscious of choice between two non-confusing behaviors: either modify the input and return nothing, or not modify the input and return the result as a new object.



            Insert k items at the start of an array in one step instead of one item in k steps



            In most programming languages, and I think in the context of this exercise, "array" usually means a contiguous area of memory. Inserting an element at the start is implemented by copying existing elements to shift them in memory by 1 position.



            For this reason, for a solution to the array rotation problem, I would avoid repeatedly inserting elements at the start of the array, to avoid repeated copying of elements. Even if arrays in JavaScript may behave differently, I would prefer a solution that doesn't raise questions about the potential underlying implementation of arrays, and looks objectively easier to accept.



            That is, I would prefer to store k values in temporary storage, shift the other elements by k steps (iterating over them only once), and then copy back the k elements to the correct positions.



            function rotate(nums, k) {
            k %= nums.length;
            const rotated = new Array(nums.length);
            for (let i = 0; i < k; i++) {
            rotated[i] = nums[nums.length - k + i];
            }
            for (let i = 0; i < nums.length - k; i++) {
            rotated[i + k] = nums[i];
            }
            return rotated;
            }


            This is $O(n)$ in both time and space.
            The extra space is needed to avoid modifying the input.
            If we preferred modifying the input,
            then only $O(k)$ extra space would be needed,
            for temporary storage of elements that would be overwritten.



            Taking advantage of JavaScript's features



            Slightly more expensive in terms of time and space,
            but my preferred solution would make better use of the built-in functions on arrays in JavaScript,
            in much more compact code:



            function rotate(nums, k) {
            k %= nums.length;
            const m = nums.length - k;
            return nums.slice(m).concat(nums.slice(0, m));
            }





            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',
              autoActivateHeartbeat: false,
              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
              });


              }
              });






              davidatthepark is a new contributor. Be nice, and check out our Code of Conduct.










              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210530%2fleetcode-189-rotate-array%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              3 Answers
              3






              active

              oldest

              votes








              3 Answers
              3






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              3














              Review



              Not bad, but there is room for a few improvements to avoid some possible problematic input arguments.



              Style



              Some points on your code.




              • The names nums and k could be better, maybe array and rotateBy

              • Try to avoid one use variables unless it makes the lines using them to long. Thus you can pop and unshift in one line nums.unshift(nums.pop());

              • Idiomatic javascript uses zero based loop counters rather than starting at 1. Thus the loop would be for (let i = 0; i < k; i++) {


              Complexity



              Your complexity is $O(n)$ and storage $O(1)$ where $n$ is the number of rotations, the range $n>0$



              However consider the next examples



              rotate([1,2,3,4,5,6,7,8,9], 18); // Will rotate 18 times same as rotate 0
              rotate([1,2,3,4,5,6,7,8,9], 8); // Will rotate 8 times same as rotate left 1
              rotate([1], 8e9); // Will spend a lot of time not changing anything


              Your function will do too much work if the rotations are outside the expected ranges, the rotation can be done in reverse in less steps, or rotating has no effect.



              You can limit the complexity to $O(k)$ where $0<k<=n/2$



              Rewrite



              This is a slight improvement on your function to ensure you don't rotate more than needed.



              function rotate(array, rotateBy) {
              rotateBy %= array.length;
              if (rotateBy < array.length - rotateBy) {
              while (rotateBy--) { array.unshift(array.pop()) }
              } else {
              rotateBy = array.length - rotateBy;
              while (rotateBy--) { array.push(array.shift()) }
              }
              return array;
              }


              Update



              As vnp's answer points out the complexity of Array.unshift and Array.shift is not as simple as $O(1)$ and will depend on the array type. We can assume the best case for this problem, sparse array (effectively a hash table) and thus will grow/shrink down at $O(1)$



              In that case the function above has a mean complexity of $O(log(n))$ of all possible values of $k$



              Note that if the cost of grow/shrink operations is $O(n)$ (dense array) this will add $n$ operations for each $k$ making the above $O(kn)$ with $0<=k<(n/2)$ Expressed in terms of $n$ or $k$ only it remains $O(log(n))$ or $O(k)$





              You could also use Array.splice



               array.unshift(...array.splice(-rotateBy,rotateBy));


              However under the hood the complexity would be a little greater $O(2n)$ (which is still $O(n)$) as splice steps over each item to remove and add to a new array. Then ... steps over them again to unshift each item to the array.



              The storage would also increase as the spliced array is held in memory until the code has finished unshifting them making storage $O(n)$



              If the array contained all the same values the rotation would have no effect thus all rotation could be done in O(1). However there is no way to know this without checking each item in turn.






              share|improve this answer




























                3














                Review



                Not bad, but there is room for a few improvements to avoid some possible problematic input arguments.



                Style



                Some points on your code.




                • The names nums and k could be better, maybe array and rotateBy

                • Try to avoid one use variables unless it makes the lines using them to long. Thus you can pop and unshift in one line nums.unshift(nums.pop());

                • Idiomatic javascript uses zero based loop counters rather than starting at 1. Thus the loop would be for (let i = 0; i < k; i++) {


                Complexity



                Your complexity is $O(n)$ and storage $O(1)$ where $n$ is the number of rotations, the range $n>0$



                However consider the next examples



                rotate([1,2,3,4,5,6,7,8,9], 18); // Will rotate 18 times same as rotate 0
                rotate([1,2,3,4,5,6,7,8,9], 8); // Will rotate 8 times same as rotate left 1
                rotate([1], 8e9); // Will spend a lot of time not changing anything


                Your function will do too much work if the rotations are outside the expected ranges, the rotation can be done in reverse in less steps, or rotating has no effect.



                You can limit the complexity to $O(k)$ where $0<k<=n/2$



                Rewrite



                This is a slight improvement on your function to ensure you don't rotate more than needed.



                function rotate(array, rotateBy) {
                rotateBy %= array.length;
                if (rotateBy < array.length - rotateBy) {
                while (rotateBy--) { array.unshift(array.pop()) }
                } else {
                rotateBy = array.length - rotateBy;
                while (rotateBy--) { array.push(array.shift()) }
                }
                return array;
                }


                Update



                As vnp's answer points out the complexity of Array.unshift and Array.shift is not as simple as $O(1)$ and will depend on the array type. We can assume the best case for this problem, sparse array (effectively a hash table) and thus will grow/shrink down at $O(1)$



                In that case the function above has a mean complexity of $O(log(n))$ of all possible values of $k$



                Note that if the cost of grow/shrink operations is $O(n)$ (dense array) this will add $n$ operations for each $k$ making the above $O(kn)$ with $0<=k<(n/2)$ Expressed in terms of $n$ or $k$ only it remains $O(log(n))$ or $O(k)$





                You could also use Array.splice



                 array.unshift(...array.splice(-rotateBy,rotateBy));


                However under the hood the complexity would be a little greater $O(2n)$ (which is still $O(n)$) as splice steps over each item to remove and add to a new array. Then ... steps over them again to unshift each item to the array.



                The storage would also increase as the spliced array is held in memory until the code has finished unshifting them making storage $O(n)$



                If the array contained all the same values the rotation would have no effect thus all rotation could be done in O(1). However there is no way to know this without checking each item in turn.






                share|improve this answer


























                  3












                  3








                  3






                  Review



                  Not bad, but there is room for a few improvements to avoid some possible problematic input arguments.



                  Style



                  Some points on your code.




                  • The names nums and k could be better, maybe array and rotateBy

                  • Try to avoid one use variables unless it makes the lines using them to long. Thus you can pop and unshift in one line nums.unshift(nums.pop());

                  • Idiomatic javascript uses zero based loop counters rather than starting at 1. Thus the loop would be for (let i = 0; i < k; i++) {


                  Complexity



                  Your complexity is $O(n)$ and storage $O(1)$ where $n$ is the number of rotations, the range $n>0$



                  However consider the next examples



                  rotate([1,2,3,4,5,6,7,8,9], 18); // Will rotate 18 times same as rotate 0
                  rotate([1,2,3,4,5,6,7,8,9], 8); // Will rotate 8 times same as rotate left 1
                  rotate([1], 8e9); // Will spend a lot of time not changing anything


                  Your function will do too much work if the rotations are outside the expected ranges, the rotation can be done in reverse in less steps, or rotating has no effect.



                  You can limit the complexity to $O(k)$ where $0<k<=n/2$



                  Rewrite



                  This is a slight improvement on your function to ensure you don't rotate more than needed.



                  function rotate(array, rotateBy) {
                  rotateBy %= array.length;
                  if (rotateBy < array.length - rotateBy) {
                  while (rotateBy--) { array.unshift(array.pop()) }
                  } else {
                  rotateBy = array.length - rotateBy;
                  while (rotateBy--) { array.push(array.shift()) }
                  }
                  return array;
                  }


                  Update



                  As vnp's answer points out the complexity of Array.unshift and Array.shift is not as simple as $O(1)$ and will depend on the array type. We can assume the best case for this problem, sparse array (effectively a hash table) and thus will grow/shrink down at $O(1)$



                  In that case the function above has a mean complexity of $O(log(n))$ of all possible values of $k$



                  Note that if the cost of grow/shrink operations is $O(n)$ (dense array) this will add $n$ operations for each $k$ making the above $O(kn)$ with $0<=k<(n/2)$ Expressed in terms of $n$ or $k$ only it remains $O(log(n))$ or $O(k)$





                  You could also use Array.splice



                   array.unshift(...array.splice(-rotateBy,rotateBy));


                  However under the hood the complexity would be a little greater $O(2n)$ (which is still $O(n)$) as splice steps over each item to remove and add to a new array. Then ... steps over them again to unshift each item to the array.



                  The storage would also increase as the spliced array is held in memory until the code has finished unshifting them making storage $O(n)$



                  If the array contained all the same values the rotation would have no effect thus all rotation could be done in O(1). However there is no way to know this without checking each item in turn.






                  share|improve this answer














                  Review



                  Not bad, but there is room for a few improvements to avoid some possible problematic input arguments.



                  Style



                  Some points on your code.




                  • The names nums and k could be better, maybe array and rotateBy

                  • Try to avoid one use variables unless it makes the lines using them to long. Thus you can pop and unshift in one line nums.unshift(nums.pop());

                  • Idiomatic javascript uses zero based loop counters rather than starting at 1. Thus the loop would be for (let i = 0; i < k; i++) {


                  Complexity



                  Your complexity is $O(n)$ and storage $O(1)$ where $n$ is the number of rotations, the range $n>0$



                  However consider the next examples



                  rotate([1,2,3,4,5,6,7,8,9], 18); // Will rotate 18 times same as rotate 0
                  rotate([1,2,3,4,5,6,7,8,9], 8); // Will rotate 8 times same as rotate left 1
                  rotate([1], 8e9); // Will spend a lot of time not changing anything


                  Your function will do too much work if the rotations are outside the expected ranges, the rotation can be done in reverse in less steps, or rotating has no effect.



                  You can limit the complexity to $O(k)$ where $0<k<=n/2$



                  Rewrite



                  This is a slight improvement on your function to ensure you don't rotate more than needed.



                  function rotate(array, rotateBy) {
                  rotateBy %= array.length;
                  if (rotateBy < array.length - rotateBy) {
                  while (rotateBy--) { array.unshift(array.pop()) }
                  } else {
                  rotateBy = array.length - rotateBy;
                  while (rotateBy--) { array.push(array.shift()) }
                  }
                  return array;
                  }


                  Update



                  As vnp's answer points out the complexity of Array.unshift and Array.shift is not as simple as $O(1)$ and will depend on the array type. We can assume the best case for this problem, sparse array (effectively a hash table) and thus will grow/shrink down at $O(1)$



                  In that case the function above has a mean complexity of $O(log(n))$ of all possible values of $k$



                  Note that if the cost of grow/shrink operations is $O(n)$ (dense array) this will add $n$ operations for each $k$ making the above $O(kn)$ with $0<=k<(n/2)$ Expressed in terms of $n$ or $k$ only it remains $O(log(n))$ or $O(k)$





                  You could also use Array.splice



                   array.unshift(...array.splice(-rotateBy,rotateBy));


                  However under the hood the complexity would be a little greater $O(2n)$ (which is still $O(n)$) as splice steps over each item to remove and add to a new array. Then ... steps over them again to unshift each item to the array.



                  The storage would also increase as the spliced array is held in memory until the code has finished unshifting them making storage $O(n)$



                  If the array contained all the same values the rotation would have no effect thus all rotation could be done in O(1). However there is no way to know this without checking each item in turn.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited 18 hours ago

























                  answered yesterday









                  Blindman67

                  7,0521521




                  7,0521521

























                      3














                      The time complexity really depends on the unshift time complexity. ECMA does not specify it, but I would expect that it is not constant. I would not be surprised if it is actually linear in the size of the array. If so, the complexity of rotate would be $O(nk)$.



                      In fact, I tested the performance of your code by timing your rotate by 1, for arrays of size from 100000 to 100000000, doubling the size every time. The results (in milliseconds) are



                      1, 3, 8, 14, 29, 33, 69, 229, 447, 926


                      I did few runs, the exact numbers were different, but consistent. You can see that as size doubles the run time (at least) doubles as well.



                      And again, it was rotation by 1. Rotation by k will take proportionally longer.





                      There are few classic algorithms which perform the rotation in true $O(n)$ complexity, that is their execution time does not depend on k. One is extremely simple to code, but takes effort to comprehend. In pseudocode:



                          reverse(0, k)
                      reverse(k, n)
                      reverse(0, n)


                      Notice that each element is moved twice. This is suboptimal. Another algorithm moves each element exactly once - right into the place where it belongs. I don't want to spoil the fun of discovering it. Try to figure it out (hint: it needs to compute gcd(n, k)).





                      That said, the leetcode problem only asks to print the rotated array. I would seriously consider to not actually perform rotation, but



                          print values from n-k to n
                      print values from 0 to n-k


                      It feels like cheating, but in fact it is valid, and sometimes very useful technique.






                      share|improve this answer























                      • JS has two types of arrays, sparse and dense. There is no programmatic way to determine what an arrays type is. Sparse arrays use a cheap hash to locate items and thus would not suffer from the need to memcpy all items up/down one position when calling Array.unshift or Array.shift It is generally assumed that these operations are O(1). Array memory allocations are never single items but rather double array size, or wait and half. Using this scheme does make it possible to have an array that can grow in both directions at O(1). Whether this is in fact done I do not know.
                        – Blindman67
                        18 hours ago
















                      3














                      The time complexity really depends on the unshift time complexity. ECMA does not specify it, but I would expect that it is not constant. I would not be surprised if it is actually linear in the size of the array. If so, the complexity of rotate would be $O(nk)$.



                      In fact, I tested the performance of your code by timing your rotate by 1, for arrays of size from 100000 to 100000000, doubling the size every time. The results (in milliseconds) are



                      1, 3, 8, 14, 29, 33, 69, 229, 447, 926


                      I did few runs, the exact numbers were different, but consistent. You can see that as size doubles the run time (at least) doubles as well.



                      And again, it was rotation by 1. Rotation by k will take proportionally longer.





                      There are few classic algorithms which perform the rotation in true $O(n)$ complexity, that is their execution time does not depend on k. One is extremely simple to code, but takes effort to comprehend. In pseudocode:



                          reverse(0, k)
                      reverse(k, n)
                      reverse(0, n)


                      Notice that each element is moved twice. This is suboptimal. Another algorithm moves each element exactly once - right into the place where it belongs. I don't want to spoil the fun of discovering it. Try to figure it out (hint: it needs to compute gcd(n, k)).





                      That said, the leetcode problem only asks to print the rotated array. I would seriously consider to not actually perform rotation, but



                          print values from n-k to n
                      print values from 0 to n-k


                      It feels like cheating, but in fact it is valid, and sometimes very useful technique.






                      share|improve this answer























                      • JS has two types of arrays, sparse and dense. There is no programmatic way to determine what an arrays type is. Sparse arrays use a cheap hash to locate items and thus would not suffer from the need to memcpy all items up/down one position when calling Array.unshift or Array.shift It is generally assumed that these operations are O(1). Array memory allocations are never single items but rather double array size, or wait and half. Using this scheme does make it possible to have an array that can grow in both directions at O(1). Whether this is in fact done I do not know.
                        – Blindman67
                        18 hours ago














                      3












                      3








                      3






                      The time complexity really depends on the unshift time complexity. ECMA does not specify it, but I would expect that it is not constant. I would not be surprised if it is actually linear in the size of the array. If so, the complexity of rotate would be $O(nk)$.



                      In fact, I tested the performance of your code by timing your rotate by 1, for arrays of size from 100000 to 100000000, doubling the size every time. The results (in milliseconds) are



                      1, 3, 8, 14, 29, 33, 69, 229, 447, 926


                      I did few runs, the exact numbers were different, but consistent. You can see that as size doubles the run time (at least) doubles as well.



                      And again, it was rotation by 1. Rotation by k will take proportionally longer.





                      There are few classic algorithms which perform the rotation in true $O(n)$ complexity, that is their execution time does not depend on k. One is extremely simple to code, but takes effort to comprehend. In pseudocode:



                          reverse(0, k)
                      reverse(k, n)
                      reverse(0, n)


                      Notice that each element is moved twice. This is suboptimal. Another algorithm moves each element exactly once - right into the place where it belongs. I don't want to spoil the fun of discovering it. Try to figure it out (hint: it needs to compute gcd(n, k)).





                      That said, the leetcode problem only asks to print the rotated array. I would seriously consider to not actually perform rotation, but



                          print values from n-k to n
                      print values from 0 to n-k


                      It feels like cheating, but in fact it is valid, and sometimes very useful technique.






                      share|improve this answer














                      The time complexity really depends on the unshift time complexity. ECMA does not specify it, but I would expect that it is not constant. I would not be surprised if it is actually linear in the size of the array. If so, the complexity of rotate would be $O(nk)$.



                      In fact, I tested the performance of your code by timing your rotate by 1, for arrays of size from 100000 to 100000000, doubling the size every time. The results (in milliseconds) are



                      1, 3, 8, 14, 29, 33, 69, 229, 447, 926


                      I did few runs, the exact numbers were different, but consistent. You can see that as size doubles the run time (at least) doubles as well.



                      And again, it was rotation by 1. Rotation by k will take proportionally longer.





                      There are few classic algorithms which perform the rotation in true $O(n)$ complexity, that is their execution time does not depend on k. One is extremely simple to code, but takes effort to comprehend. In pseudocode:



                          reverse(0, k)
                      reverse(k, n)
                      reverse(0, n)


                      Notice that each element is moved twice. This is suboptimal. Another algorithm moves each element exactly once - right into the place where it belongs. I don't want to spoil the fun of discovering it. Try to figure it out (hint: it needs to compute gcd(n, k)).





                      That said, the leetcode problem only asks to print the rotated array. I would seriously consider to not actually perform rotation, but



                          print values from n-k to n
                      print values from 0 to n-k


                      It feels like cheating, but in fact it is valid, and sometimes very useful technique.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited 13 hours ago









                      mdfst13

                      17.4k52156




                      17.4k52156










                      answered yesterday









                      vnp

                      38.5k13097




                      38.5k13097












                      • JS has two types of arrays, sparse and dense. There is no programmatic way to determine what an arrays type is. Sparse arrays use a cheap hash to locate items and thus would not suffer from the need to memcpy all items up/down one position when calling Array.unshift or Array.shift It is generally assumed that these operations are O(1). Array memory allocations are never single items but rather double array size, or wait and half. Using this scheme does make it possible to have an array that can grow in both directions at O(1). Whether this is in fact done I do not know.
                        – Blindman67
                        18 hours ago


















                      • JS has two types of arrays, sparse and dense. There is no programmatic way to determine what an arrays type is. Sparse arrays use a cheap hash to locate items and thus would not suffer from the need to memcpy all items up/down one position when calling Array.unshift or Array.shift It is generally assumed that these operations are O(1). Array memory allocations are never single items but rather double array size, or wait and half. Using this scheme does make it possible to have an array that can grow in both directions at O(1). Whether this is in fact done I do not know.
                        – Blindman67
                        18 hours ago
















                      JS has two types of arrays, sparse and dense. There is no programmatic way to determine what an arrays type is. Sparse arrays use a cheap hash to locate items and thus would not suffer from the need to memcpy all items up/down one position when calling Array.unshift or Array.shift It is generally assumed that these operations are O(1). Array memory allocations are never single items but rather double array size, or wait and half. Using this scheme does make it possible to have an array that can grow in both directions at O(1). Whether this is in fact done I do not know.
                      – Blindman67
                      18 hours ago




                      JS has two types of arrays, sparse and dense. There is no programmatic way to determine what an arrays type is. Sparse arrays use a cheap hash to locate items and thus would not suffer from the need to memcpy all items up/down one position when calling Array.unshift or Array.shift It is generally assumed that these operations are O(1). Array memory allocations are never single items but rather double array size, or wait and half. Using this scheme does make it possible to have an array that can grow in both directions at O(1). Whether this is in fact done I do not know.
                      – Blindman67
                      18 hours ago











                      1














                      Think twice before modifying function parameters



                      The posted code modifies the content of the input array nums and also returns it.
                      When a function returns something,
                      it can be confusing if it also modifies the input — a side effect.
                      Modifying the input and not returning anything (void in other programming languages) is not confusing.
                      I think it's important to make a conscious of choice between two non-confusing behaviors: either modify the input and return nothing, or not modify the input and return the result as a new object.



                      Insert k items at the start of an array in one step instead of one item in k steps



                      In most programming languages, and I think in the context of this exercise, "array" usually means a contiguous area of memory. Inserting an element at the start is implemented by copying existing elements to shift them in memory by 1 position.



                      For this reason, for a solution to the array rotation problem, I would avoid repeatedly inserting elements at the start of the array, to avoid repeated copying of elements. Even if arrays in JavaScript may behave differently, I would prefer a solution that doesn't raise questions about the potential underlying implementation of arrays, and looks objectively easier to accept.



                      That is, I would prefer to store k values in temporary storage, shift the other elements by k steps (iterating over them only once), and then copy back the k elements to the correct positions.



                      function rotate(nums, k) {
                      k %= nums.length;
                      const rotated = new Array(nums.length);
                      for (let i = 0; i < k; i++) {
                      rotated[i] = nums[nums.length - k + i];
                      }
                      for (let i = 0; i < nums.length - k; i++) {
                      rotated[i + k] = nums[i];
                      }
                      return rotated;
                      }


                      This is $O(n)$ in both time and space.
                      The extra space is needed to avoid modifying the input.
                      If we preferred modifying the input,
                      then only $O(k)$ extra space would be needed,
                      for temporary storage of elements that would be overwritten.



                      Taking advantage of JavaScript's features



                      Slightly more expensive in terms of time and space,
                      but my preferred solution would make better use of the built-in functions on arrays in JavaScript,
                      in much more compact code:



                      function rotate(nums, k) {
                      k %= nums.length;
                      const m = nums.length - k;
                      return nums.slice(m).concat(nums.slice(0, m));
                      }





                      share|improve this answer


























                        1














                        Think twice before modifying function parameters



                        The posted code modifies the content of the input array nums and also returns it.
                        When a function returns something,
                        it can be confusing if it also modifies the input — a side effect.
                        Modifying the input and not returning anything (void in other programming languages) is not confusing.
                        I think it's important to make a conscious of choice between two non-confusing behaviors: either modify the input and return nothing, or not modify the input and return the result as a new object.



                        Insert k items at the start of an array in one step instead of one item in k steps



                        In most programming languages, and I think in the context of this exercise, "array" usually means a contiguous area of memory. Inserting an element at the start is implemented by copying existing elements to shift them in memory by 1 position.



                        For this reason, for a solution to the array rotation problem, I would avoid repeatedly inserting elements at the start of the array, to avoid repeated copying of elements. Even if arrays in JavaScript may behave differently, I would prefer a solution that doesn't raise questions about the potential underlying implementation of arrays, and looks objectively easier to accept.



                        That is, I would prefer to store k values in temporary storage, shift the other elements by k steps (iterating over them only once), and then copy back the k elements to the correct positions.



                        function rotate(nums, k) {
                        k %= nums.length;
                        const rotated = new Array(nums.length);
                        for (let i = 0; i < k; i++) {
                        rotated[i] = nums[nums.length - k + i];
                        }
                        for (let i = 0; i < nums.length - k; i++) {
                        rotated[i + k] = nums[i];
                        }
                        return rotated;
                        }


                        This is $O(n)$ in both time and space.
                        The extra space is needed to avoid modifying the input.
                        If we preferred modifying the input,
                        then only $O(k)$ extra space would be needed,
                        for temporary storage of elements that would be overwritten.



                        Taking advantage of JavaScript's features



                        Slightly more expensive in terms of time and space,
                        but my preferred solution would make better use of the built-in functions on arrays in JavaScript,
                        in much more compact code:



                        function rotate(nums, k) {
                        k %= nums.length;
                        const m = nums.length - k;
                        return nums.slice(m).concat(nums.slice(0, m));
                        }





                        share|improve this answer
























                          1












                          1








                          1






                          Think twice before modifying function parameters



                          The posted code modifies the content of the input array nums and also returns it.
                          When a function returns something,
                          it can be confusing if it also modifies the input — a side effect.
                          Modifying the input and not returning anything (void in other programming languages) is not confusing.
                          I think it's important to make a conscious of choice between two non-confusing behaviors: either modify the input and return nothing, or not modify the input and return the result as a new object.



                          Insert k items at the start of an array in one step instead of one item in k steps



                          In most programming languages, and I think in the context of this exercise, "array" usually means a contiguous area of memory. Inserting an element at the start is implemented by copying existing elements to shift them in memory by 1 position.



                          For this reason, for a solution to the array rotation problem, I would avoid repeatedly inserting elements at the start of the array, to avoid repeated copying of elements. Even if arrays in JavaScript may behave differently, I would prefer a solution that doesn't raise questions about the potential underlying implementation of arrays, and looks objectively easier to accept.



                          That is, I would prefer to store k values in temporary storage, shift the other elements by k steps (iterating over them only once), and then copy back the k elements to the correct positions.



                          function rotate(nums, k) {
                          k %= nums.length;
                          const rotated = new Array(nums.length);
                          for (let i = 0; i < k; i++) {
                          rotated[i] = nums[nums.length - k + i];
                          }
                          for (let i = 0; i < nums.length - k; i++) {
                          rotated[i + k] = nums[i];
                          }
                          return rotated;
                          }


                          This is $O(n)$ in both time and space.
                          The extra space is needed to avoid modifying the input.
                          If we preferred modifying the input,
                          then only $O(k)$ extra space would be needed,
                          for temporary storage of elements that would be overwritten.



                          Taking advantage of JavaScript's features



                          Slightly more expensive in terms of time and space,
                          but my preferred solution would make better use of the built-in functions on arrays in JavaScript,
                          in much more compact code:



                          function rotate(nums, k) {
                          k %= nums.length;
                          const m = nums.length - k;
                          return nums.slice(m).concat(nums.slice(0, m));
                          }





                          share|improve this answer












                          Think twice before modifying function parameters



                          The posted code modifies the content of the input array nums and also returns it.
                          When a function returns something,
                          it can be confusing if it also modifies the input — a side effect.
                          Modifying the input and not returning anything (void in other programming languages) is not confusing.
                          I think it's important to make a conscious of choice between two non-confusing behaviors: either modify the input and return nothing, or not modify the input and return the result as a new object.



                          Insert k items at the start of an array in one step instead of one item in k steps



                          In most programming languages, and I think in the context of this exercise, "array" usually means a contiguous area of memory. Inserting an element at the start is implemented by copying existing elements to shift them in memory by 1 position.



                          For this reason, for a solution to the array rotation problem, I would avoid repeatedly inserting elements at the start of the array, to avoid repeated copying of elements. Even if arrays in JavaScript may behave differently, I would prefer a solution that doesn't raise questions about the potential underlying implementation of arrays, and looks objectively easier to accept.



                          That is, I would prefer to store k values in temporary storage, shift the other elements by k steps (iterating over them only once), and then copy back the k elements to the correct positions.



                          function rotate(nums, k) {
                          k %= nums.length;
                          const rotated = new Array(nums.length);
                          for (let i = 0; i < k; i++) {
                          rotated[i] = nums[nums.length - k + i];
                          }
                          for (let i = 0; i < nums.length - k; i++) {
                          rotated[i + k] = nums[i];
                          }
                          return rotated;
                          }


                          This is $O(n)$ in both time and space.
                          The extra space is needed to avoid modifying the input.
                          If we preferred modifying the input,
                          then only $O(k)$ extra space would be needed,
                          for temporary storage of elements that would be overwritten.



                          Taking advantage of JavaScript's features



                          Slightly more expensive in terms of time and space,
                          but my preferred solution would make better use of the built-in functions on arrays in JavaScript,
                          in much more compact code:



                          function rotate(nums, k) {
                          k %= nums.length;
                          const m = nums.length - k;
                          return nums.slice(m).concat(nums.slice(0, m));
                          }






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered 11 hours ago









                          janos

                          97.2k12124350




                          97.2k12124350






















                              davidatthepark is a new contributor. Be nice, and check out our Code of Conduct.










                              draft saved

                              draft discarded


















                              davidatthepark is a new contributor. Be nice, and check out our Code of Conduct.













                              davidatthepark is a new contributor. Be nice, and check out our Code of Conduct.












                              davidatthepark is a new contributor. Be nice, and check out our Code of Conduct.
















                              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%2f210530%2fleetcode-189-rotate-array%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

                              Morgemoulin

                              Scott Moir

                              Souastre