479. Remove Comments
You are given a C++ program as source, a list of strings where source[i] is the i-th physical line of the file.
Strip every comment from it:
//starts a line comment — it and everything after it on that physical line is dead./*starts a block comment — it, everything up to the next*/(possibly many lines later), and the closing*/are all dead.
Markers only count when you are not already inside a comment: a // or /* sitting inside an open block comment is plain text, and a /* appearing after a // on the same line is already dead. When markers overlap, the leftmost one that begins first wins. The */ that closes a block must come strictly after the /* that opened it — the middle character of /*/ does not close anything.
After deletion, code that was separated only by a block comment fuses into a single line (the text before /* and the text after */ join), and any line left empty vanishes. Return the surviving lines, in order, as a list of strings.
The input contains no string literals or quote characters, and every block comment that opens is eventually closed.
Example 1:
Input: source = ["int a = 1;// set a", "int b;/* declare", "b */int c;"]
Output: ["int a = 1;", "int b;int c;"]
Explanation: Line 1 loses its line comment. Line 2 keeps "int b;" and opens a block comment that swallows the rest of line 2 and the start of line 3; when it closes, "int c;" glues onto the pending "int b;" to form one fused line.
Example 2:
Input: source = ["void f() {/* comment // still comment", "more */}", "// gone /* not a block", "int z;"]
Output: ["void f() {}", "int z;"]
Explanation: The // inside the open block comment is plain text, so the block runs until the */ on line 2, fusing "void f() {" with "}". Line 3 starts with //, so the /* after it never opens a block and the whole line dies, leaving nothing — the empty line is dropped.
Constraints:
- 1 ≤ source.length ≤ 100
- 1 ≤ source[i].length ≤ 80
- source[i] consists of printable ASCII characters and contains no quote characters.
- Every block comment that opens is eventually closed, and no closing */ appears without a matching opener.
Hints:
One boolean is the whole state: "am I inside a block comment right now?" It must survive from one line to the next.
Scan each line with an index and look at two characters at a time. Outside a block: "//" kills the rest of the line, "/*" flips the flag and skips 2 characters. Inside a block: only "*/" matters (skip 2 when you see it); every other character is discarded. After opening with "/*", continue past both characters so the '/' of "/*/" can't double as a closer.
Keep a growing buffer of kept characters that you only flush at the end of a line when you are NOT inside a block — that single rule produces the line-fusing behavior for free, and flushing only non-empty buffers drops the empty lines.
▶ Run checks these sample cases. Submit also runs hidden edge cases.
Input: source = ["int a = 1;// set a", "int b;/* declare", "b */int c;"]
Expected output: ["int a = 1;", "int b;int c;"]