As pointed out in comments, the biggest issue here is the misconception that a std::string
is merely a simple wrapper around a C-string. The issue is the idea that inserting a null character will terminate your string for you. A simple demo:
#include <iostream>
#include <string>
int main() {
std::string num{"123456789"};
num[4] = '\0'; // Overwriting the 5
std::cout << num << '\n';
}
Output:
// The '\0' didn't end the string, it just disappeared the 5
12346789
So, we've shown that the null character tactic won't work. Let's instead return a new string.
class Solution {
public:
std::string largestOddNumber(std::string_view num) {
for (int i = num.length() - 1; i >= 0; --i) {
if ((num[i] - '0') & 1) {
return std::string(num.begin(), num.begin() + i + 1);
}
}
// If the loop ends naturally, we never found an odd number
return "";
}
};
The results are:
Runtime: 22ms (beats 83.83%)
Memory: 13.7MB (beats 99.76%)
I haven't looked at the posted solutions, but I'm satisfied with the results. I may take a gander because I enjoy learning about some of these algorithms and the various ways they can be applied.
A big time-save for determining if a value is odd is the bitwise AND with 1
. If there's a faster way, I don't know it. And I'm not being facetious; if someone knows a faster way then I am happy to learn. But any human-readable binary representation of an odd number will have the rightmost bit set to 1
. It's one comparison versus the five in your code. If I find an odd number, I return a newly constructed string from the beginning of num
to where the odd number was found.
I also changed the parameter type to std::string_view
. It's much more efficient when passing a read-only string around. Changin the return type to std::string_view
would make a lot of sense outside of leetcode, but since they were expecting a std::string
, it would have just been an extra type conversion. So I avoided it.
Edit: I took a look. A few solutions modify num
directly by popping off the last character if it's even and eventually returning num
directly. In one attempt, it ran slower by about 5ms and consumed a tiny amount (0.09MB) more RAM. But, if I submitted a few times, I'd probably get runtimes similar to my original result. But why bother when I have my original result?
Looking further, I'm surprised that code using modulo operators is faster than mine. I guess the "new-fangled" CPUs can now do it intrinsically. One of the fastest solutions just did a bunch of hacky garbage, and I wouldn't bother with any of that unless performance above all else was the goal.