Part 1 · Lesson 5 · 18 min read
The while Loop
Repeat while a condition is true. Taking a number apart digit by digit, and a clear rule for choosing between for and while.
On this page
Repeat while a condition is true
A for loop is perfect when you know the range, such as 1 to N or 0 to length − 1. But sometimes you only know the stopping condition. Examples are “keep dividing until nothing is left”, “keep doubling until you pass 1000” and “keep asking until the password is right”. For these, use a while loop. A while loop is a loop that repeats its body for as long as a condition stays true.
The while loop, next to for
// for: start, check and update all in one linefor (let i = 1; i <= 3; i++) { console.log(i);}// while: the same loop with the three parts spread outlet i = 1; // start (before the loop)while (i <= 3) { // check console.log(i); i++; // update (last line of the body — easy to forget!)}/* Output:123123*/A while loop has only the check in its brackets. The start goes before the loop. The update goes inside the body, usually as the last line. The order of execution from Lesson 4 is the same: check, body, check, body, and so on, until a check fails and the loop ends.
The digit loop: n % 10 and Math.floor(n / 10)
A digit is one of the symbols 0 to 9 that make up a number. The number 472 has three digits. In Lesson 2 you took the digits off a three-digit number by writing the same two lines three times. A while loop can do it for a number of any length, because it keeps going until there are no digits left:
while (n > 0) {
const digit = n % 10; // the last digit
// ...use digit...
n = Math.floor(n / 10); // remove the last digit
}Counting digits, adding digits, reversing a number, checking a palindrome number and finding Armstrong numbers all use this same loop. Only the line in the middle is different.
Traced: the sum of the digits of 472
The number to take apart.
▶let n = 472;2let sum = 0;3while (n > 0) {4 sum += n % 10;5 n = Math.floor(n / 10);6}7console.log(sum);| n | 472 |
| n at check | n > 0? | n % 10 | sum after | n after |
|---|---|---|---|---|
| 472 | true | 2 | 2 | 47 |
| 47 | true | 7 | 9 | 4 |
| 4 | true | 4 | 13 | 0 |
| 0 | false | — | 13 | (loop ends) |
Building a number: reverse
Taking digits apart is half the skill. The other half is putting them back together. To reverse a number, you build a new number, rev, one digit at a time. rev * 10 moves every digit of rev one place to the left. This makes an empty place at the end. Then + digit fills that place.
let n = 1234;let rev = 0;while (n > 0) { const digit = n % 10; // take the last digit rev = rev * 10 + digit; // shift rev left, put the digit on the end n = Math.floor(n / 10); // drop the last digit}console.log(rev); // 4321| n | digit = n % 10 | rev = rev * 10 + digit | n after |
|---|---|---|---|
| 1234 | 4 | 0 × 10 + 4 = 4 | 123 |
| 123 | 3 | 4 × 10 + 3 = 43 | 12 |
| 12 | 2 | 43 × 10 + 2 = 432 | 1 |
| 1 | 1 | 432 × 10 + 1 = 4321 | 0 |
Infinite loops, and how to avoid them
A while loop stops only when its condition becomes false. If nothing in the body moves towards that, the loop runs forever. This is called an infinite loop:
let i = 1;while (i <= 5) { console.log(i); // i++ is missing, so i stays 1 and 1 is printed forever. Press Ctrl+C to stop.}Before running any while loop, ask one question:
Find that line. In the digit loop it is n = Math.floor(n / 10). The number n becomes smaller in every iteration, so it must reach 0. If you cannot point at such a line, you probably have an infinite loop. If one is already running, press Ctrl+C in the terminal to stop it.
do … while (rarely needed)
do { … } while (condition) is a loop that runs the body first and checks the condition afterwards. So the body always runs at least once. It helps in a case like the one below, where the number 0 still has one digit. But you will rarely need it in DSA.
let n = 0;let digits = 0;do { digits++; n = Math.floor(n / 10);} while (n > 0);console.log(digits); // 1 (0 has one digit; a plain while would say 0)for or while? A simple rule
| If you know… | Use | Examples |
|---|---|---|
| the range of values (from … to …) | for | 1 to N, every item of an array, every character of a string |
| only when to stop | while | until n is 0, until a value passes a limit, two pointers meeting in the middle (Lesson 21) |
Anything one loop can do, the other can do too. This rule only helps you pick the one that is easier to read.
Practice questions
Count how many digits a non-negative whole number has.
Hint 1
Hint 2
Show all 3 solutions with explanations
Remove one digit in each iteration with Math.floor(n / 10), and count the iterations.
function countDigits(n) { if (n === 0) return 1; // the loop below would not run for 0 let count = 0; while (n > 0) { count++; n = Math.floor(n / 10); } return count;}console.log(countDigits(4729)); // 4console.log(countDigits(7)); // 1console.log(countDigits(0)); // 1| n at check | count after | n after |
|---|---|---|
| 4729 | 1 | 472 |
| 472 | 2 | 47 |
| 47 | 3 | 4 |
| 4 | 4 | 0 |
| 0 | (loop ends) |
The number of digits is the number of characters in the number when it is written as text (a string).
function countDigits(n) { return String(n).length;}console.log(countDigits(4729)); // 4console.log(countDigits(0)); // 1String(4729) is "4729", which has length 4. It is short and correct for non-negative whole numbers.
A logarithm tells you how many times you can divide by a base. A number with k digits is at least 10k−1 and less than 10k, so k = ⌊log₁₀ n⌋ + 1. (The symbol ⌊ ⌋ means “round down”.)
function countDigits(n) { if (n === 0) return 1; return Math.floor(Math.log10(n)) + 1;}console.log(countDigits(4729)); // 4console.log(countDigits(1000)); // 4Math.log10(4729) is about 3.67. Rounding down gives 3, and adding 1 gives 4. This is a maths shortcut. It is good to know, but not required. Be careful: computers store decimals with small rounding errors, so for very large numbers (for example 999999999999999) this method can give a wrong answer.
Learn Approach 1. It is the digit loop that every other question in this list builds on. Approach 2 is fine in everyday code.
Find the sum of the digits of n.
Hint 1
n % 10.Hint 2
Math.floor(n / 10).Show all 2 solutions with explanations
Take the last digit, add it to the sum, and remove it. Repeat while digits remain.
function sumDigits(n) { let sum = 0; while (n > 0) { sum += n % 10; n = Math.floor(n / 10); } return sum;}console.log(sumDigits(4729)); // 22This is the traced example from the lesson, put inside a function. It works for a number of any length.
Write the number as text. Then turn each character into a number and add them up.
function sumDigits(n) { let sum = 0; for (const ch of String(n)) { sum += Number(ch); } return sum;}console.log(sumDigits(4729)); // 22for (const ch of text) is a loop that visits every character of the text one by one (Lesson 9). Number("7") turns the character into the number 7.
Interviewers usually expect Approach 1, because it uses numbers only. Approach 2 is also correct and easy to read.
Reverse the digits of a positive number.
Hint 1
Hint 2
rev, multiply rev by 10 and add the digit: rev = rev * 10 + digit.Show all 2 solutions with explanations
Take the last digit of n and attach it to the end of rev. Repeat until n is 0.
function reverseNumber(n) { let rev = 0; while (n > 0) { rev = rev * 10 + (n % 10); n = Math.floor(n / 10); } return rev;}console.log(reverseNumber(1234)); // 4321console.log(reverseNumber(1200)); // 21| n | digit | rev = rev × 10 + digit |
|---|---|---|
| 1234 | 4 | 4 |
| 123 | 3 | 43 |
| 12 | 2 | 432 |
| 1 | 1 | 4321 |
Turn the number into text, reverse the characters, and turn the result back into a number.
function reverseNumber(n) { return Number(String(n).split("").reverse().join(""));}console.log(reverseNumber(1234)); // 4321console.log(reverseNumber(1200)); // 21split("") makes a list of single characters. reverse() reverses the list. join("") joins the list back into text. Number("0021") is 21.
Approach 1 is the answer interviewers expect. LeetCode 7 (Reverse Integer) adds negative numbers and a size limit (the result must fit in a 32-bit integer). Handle the sign separately and check the limit before you return.
Return true if the number reads the same forwards and backwards. (LeetCode 9.)
Hint 1
Hint 2
Show all 3 solutions with explanations
Build the reverse of n, then check whether it equals the original.
function isPalindromeNumber(n) { const original = n; // the loop will change n let rev = 0; while (n > 0) { rev = rev * 10 + (n % 10); n = Math.floor(n / 10); } return rev === original;}console.log(isPalindromeNumber(121)); // trueconsole.log(isPalindromeNumber(123)); // falseconsole.log(isPalindromeNumber(10)); // falseA common bug is comparing rev === n after the loop. By then n is 0. Saving original first fixes it.
Write the number as text. Compare the first and last characters, then move both positions towards the middle.
function isPalindromeNumber(n) { const s = String(n); let left = 0, right = s.length - 1; while (left < right) { if (s[left] !== s[right]) return false; left++; right--; } return true;}console.log(isPalindromeNumber(1221)); // trueconsole.log(isPalindromeNumber(123)); // falseThis is the two pointers technique. A pointer here is just a variable that holds a position (left and right). You will meet this technique again in Lessons 8, 9 and 21. The loop stops at the first mismatch.
Move digits from n into rev until rev is at least as large as n. At that point you have reversed half of the number. Then compare the two halves.
function isPalindromeNumber(n) { if (n < 0 || (n % 10 === 0 && n !== 0)) return false; // e.g. 10, 120 let rev = 0; while (n > rev) { rev = rev * 10 + (n % 10); n = Math.floor(n / 10); } // even length: n === rev; odd length: drop the middle digit from rev return n === rev || n === Math.floor(rev / 10);}console.log(isPalindromeNumber(1221)); // trueconsole.log(isPalindromeNumber(12321)); // trueconsole.log(isPalindromeNumber(10)); // falseFor 12321: after three iterations n = 12 and rev = 123; Math.floor(123 / 10) = 12 = n, so it is a palindrome. Only half of the digits are processed, and the reversed number can never become too large. This is the follow-up answer for LeetCode 9.
Start with Approach 1, because it is clear and correct. If the interviewer says not to convert to text, use Approach 1 or 3. Approach 3 is the most efficient.
Find the smallest power of 2 (1, 2, 4, 8, …) that is greater than or equal to N.
Hint 1
Hint 2
Show all 2 solutions with explanations
Start at 1 and multiply by 2 until the value is at least N.
function nextPowerOfTwo(N) { let p = 1; while (p < N) { p *= 2; } return p;}console.log(nextPowerOfTwo(20)); // 32console.log(nextPowerOfTwo(64)); // 64console.log(nextPowerOfTwo(1)); // 1Use p < N, not p <= N; otherwise for N = 64 the loop doubles once more and returns 128.
The power you need is ⌈log₂ N⌉ (the logarithm to base 2, rounded up). The answer is 2 raised to that power.
function nextPowerOfTwo(N) { return 2 ** Math.ceil(Math.log2(N));}console.log(nextPowerOfTwo(20)); // 32console.log(nextPowerOfTwo(64)); // 64Math.log2(20) is about 4.32. Rounding up gives 5, and 2⁵ = 32. This is a one-line maths shortcut. For very large N (above about 5 × 10¹⁴), rounding errors in decimals can make it give a wrong answer.
Approach 1 is the clearest example of when to use while. Approach 2 is shorter, but you need to remember the maths.
How many digits of n are even?
Hint 1
Hint 2
Show all 2 solutions with explanations
Take each digit with n % 10; count it if digit % 2 === 0.
function countEvenDigits(n) { let count = 0; while (n > 0) { const digit = n % 10; if (digit % 2 === 0) count++; n = Math.floor(n / 10); } return count;}console.log(countEvenDigits(4729)); // 2console.log(countEvenDigits(2468)); // 4This combines Lessons 3 and 5: a condition inside the digit loop. Most real problems are made of small building blocks like this.
Check each character of the number when it is written as text.
function countEvenDigits(n) { let count = 0; for (const ch of String(n)) { if (Number(ch) % 2 === 0) count++; } return count;}console.log(countEvenDigits(4729)); // 2This is the same idea, but it reads the digits from left to right instead of right to left. The order does not matter for counting.
Both are correct. Approach 1 uses only arithmetic (maths with numbers), which is what most interviewers expect for digit questions.
An Armstrong number is a number that equals the sum of its digits, each raised to the power of the number of digits. Check whether n is one.
Hint 1
Hint 2
Show all 2 solutions with explanations
- Count the digits (k) using a copy of n.
- Loop again, adding each digit to the power k.
- Compare the sum with the original number.
function isArmstrong(n) { const original = n; let k = 0, temp = n; // pass 1: count digits on a copy while (temp > 0) { k++; temp = Math.floor(temp / 10); } let sum = 0; // pass 2: sum of digit^k while (n > 0) { sum += (n % 10) ** k; n = Math.floor(n / 10); } return sum === original;}console.log(isArmstrong(153)); // trueconsole.log(isArmstrong(9474)); // trueconsole.log(isArmstrong(123)); // falseThe first loop uses its own copy (temp), so n is still unchanged when the second loop runs. Splitting a problem into two simple passes is a good interview answer.
Get the digit count from the length of the text, then do a single digit loop.
function isArmstrong(n) { const k = String(n).length; let sum = 0, temp = n; while (temp > 0) { sum += (temp % 10) ** k; temp = Math.floor(temp / 10); } return sum === n;}console.log(isArmstrong(153)); // trueconsole.log(isArmstrong(370)); // trueThis is shorter, with one loop instead of two. Working on temp keeps n available for the final comparison.
Both are correct. Approach 2 is shorter. Approach 1 shows that you can do everything with arithmetic, which some interviewers ask for.
If n is even, halve it. If n is odd, make it 3n + 1. Count the steps until n becomes 1.
Hint 1
Hint 2
n !== 1. Inside the loop, apply the even or odd rule and count one step.Show all 2 solutions with explanations
Repeat until n is 1. If n is even, halve it. Otherwise make it 3n + 1. Count each step.
function collatzSteps(n) { let steps = 0; while (n !== 1) { if (n % 2 === 0) { n = n / 2; } else { n = 3 * n + 1; } steps++; } return steps;}console.log(collatzSteps(6)); // 8console.log(collatzSteps(1)); // 0This is the clearest case for while. The only thing you know is the stopping condition.
The same loop, but it picks the next value in one line with a ternary (Lesson 3).
function collatzSteps(n) { let steps = 0; while (n !== 1) { n = n % 2 === 0 ? n / 2 : 3 * n + 1; steps++; } return steps;}console.log(collatzSteps(6)); // 8This is shorter, and the update is in one place. That makes it easy to check that n changes in every iteration.
Either one is fine. Use the version that you find easier to read aloud.
Find the largest number that divides both a and b exactly. This is the greatest common divisor (GCD).
Hint 1
Hint 2
Show all 3 solutions with explanations
Start at the smaller of the two numbers and count down. The first number that divides both is the answer.
function gcd(a, b) { for (let d = Math.min(a, b); d >= 1; d--) { if (a % d === 0 && b % d === 0) return d; } return 1;}console.log(gcd(48, 18)); // 6console.log(gcd(17, 5)); // 1This is easy to understand, but for large numbers it may try millions of candidates.
Replace the pair (a, b) with (b, a % b) again and again until b is 0. Then a is the answer.
function gcd(a, b) { while (b !== 0) { const r = a % b; a = b; b = r; } return a;}console.log(gcd(48, 18)); // 6console.log(gcd(17, 5)); // 1| a | b | r = a % b |
|---|---|---|
| 48 | 18 | 12 |
| 18 | 12 | 6 |
| 12 | 6 | 0 |
| 6 | 0 | (loop ends → 6) |
Subtract the smaller number from the larger one until they are equal.
function gcd(a, b) { while (a !== b) { if (a > b) a -= b; else b -= a; } return a;}console.log(gcd(48, 18)); // 6This is the original form of the method. It gives the same answer, but % does many subtractions in one step, so Approach 2 is much faster. (This version assumes both numbers are positive.)
Use Approach 2. It is over 2,000 years old and is still the standard method. It needs very few iterations, even for huge numbers.
If n is even, divide it by 2; if it is odd, subtract 1. Return how many steps it takes to reach 0. (LeetCode 1342.)
Hint 1
Hint 2
Show all 2 solutions with explanations
Follow the rule exactly as it is described, and count the steps.
function numberOfSteps(n) { let steps = 0; while (n > 0) { n = n % 2 === 0 ? n / 2 : n - 1; steps++; } return steps;}console.log(numberOfSteps(14)); // 6console.log(numberOfSteps(8)); // 4This is a direct simulation (you do what the question says, step by step). Each even step halves n, so the loop runs only a few dozen times, even for very large numbers.
Binary is the way computers write numbers using only 0 and 1. In binary, halving an even number removes its last digit (a 0). Subtracting 1 from an odd number turns its last 1 into 0. So the number of steps is (number of binary digits − 1) + (number of 1s).
function numberOfSteps(n) { if (n === 0) return 0; const bits = n.toString(2); // 14 → "1110" let ones = 0; for (const b of bits) if (b === "1") ones++; return bits.length - 1 + ones; // 3 + 3 = 6}console.log(numberOfSteps(14)); // 6console.log(numberOfSteps(8)); // 4n.toString(2) writes n in binary. This is a preview of bit manipulation (working with the 0s and 1s of a number; Lesson 58). The simulation is perfectly fine in an interview.
Give Approach 1. Approach 2 is a nice extra point to mention if you have time.
Make it stick
- Write the digit loop from memory, and say which line guarantees it ends.
- Reverse 905 on paper with a dry-run table. (Answer: 509.)
- Rewrite
for (let i = 10; i > 0; i -= 3)as awhileloop and list the values of i.
Revisit schedule: solve two of the questions again tomorrow, again in 3 days, and once more in a week — without looking at the answers. Each time it will feel easier. That is the memory forming.
Next lesson: loops inside other loops (nested loops), and how to draw patterns with them.
Practise on LeetCode
Real interview problems that use exactly what this lesson teaches. Solve them in JavaScript after the practice questions above.
Published by Jainik · Last updated · How these lessons are made
Keep learning
Related series