I was solving a problem on leetcode with c++ and for a very big vector, i get TLE,
so the idea come to me to test with go and then i have tested with rust, still TLE.
Anyways
I thought rust would be faster or rarely same with go but
Results
C++
0.56s to compile
14.61s to execute
Go
0.23s to compile
2.66 to execute
Rust (rustc)
1.47s to compile
109.30s to execute
so i want to know how can i improve this rust code (can it beat go)
// very big vec (let v = vec![.......])
let mut ans = 0;
let n = v.len();
for i in 0..n {
for j in i+1..n {
if v[j]-v[i] > ans {
ans = v[j]-v[i];
}
}
}
println!("{}",ans);
go code
// very big vec (var v []int = []int{...........})
ans := 0
n := len(v)
for i := 0; i < n; i++ {
for j := i + 1; j < n; j++ {
if v[j]-v[i] > ans {
ans = v[j] - v[i]
}
}
}
fmt.Println(ans)
I think there's an O(n) algorithm for this problem that will be much faster than any of these.
That said, all three of these languages should be in the same ballpark as far as execution time is concerned. Are you enabling optimizations in C++ and Rust?
There is no point in computing the difference on each iteration. You can just search for the minimum and maximum, and take their difference. It should fully vectorize and be blazingly fast. There is also no point in hand-rolling the search, the standard (Iterator::max](Iterator in std::iter - Rust) and (Iterator::min](Iterator in std::iter - Rust) should do the job.
That kind of order of magnitude difference usually means you didn't enable optimizations. For Rust, you should use cargo run --release, for C++ you should compile with -O3.
Yes, sorry. I kinda pattern-matched the original question to the problem "find the greatest difference of elements", but it indeed doesn't correspond to the original algorithm.
Focussing on the algorithm itself instead of optimising Rust vs other programming languages, it is not hard to create an algorithm equivalent to the original, which runs in linear time:
fn new(v: &[i32]) -> i32
{
let n = v.len();
let mut ans = 0;
let mut greatest = v[n-1];
for &vi in v[..n-1].iter().rev()
{
if vi > greatest
{
greatest = vi;
}
else if greatest - vi > ans
{
ans = greatest - vi;
}
}
ans
}
Comparing timings with a random array of integers in the range -1_000_000..1_000_000, for 100_000 elements:
Original algorithm, answer = 1999870, time = 457 ms
New algorithm, answer = 1999870, time = 0 ms
and for 1_000_000 elements:
Original algorithm, answer = 1999994, time = 48362 ms
New algorithm, answer = 1999994, time = 0 ms
(which BTW, nicely confirms the quadratic scaling of the original code)
Yes, but it's been evident for years that a large number of beginners simply don't notice – and/or understand the implications of – the "unoptimized". It's just too technical and gets lost in the noise. Nobody reads messages that are not clearly marked as warnings or errors. And it's difficult to get people to even read and understand those! Also, I don't think it's a hyperlink in any terminal that I use at least.
I feel this could well be a Cargo lint that's warn by default, if it were easy enough to change to disable (eg. if Cargo had a git-like cargo config --global -A beginner-lints or something like that, and the lint told the user exactly what to do to disable it).
I don't think that's a surmountable problem in the general case, without making optimized builds the default.
Also, time is a shell built-in, not a parent process. I don't know that there's a sensible way to detect it, even if I thought trying to do so was a good idea.
I very much agree. For a non-beginner the Unix philosophy of "print nothing if successful" is quite user-friendly, and even a beginner only needs some indication of success. For cargo run the indication can simply be the fact that your program did, in fact, start. A beginner doesn't know the implications of "non-optimized, debuginfo", and a non-beginner almost never has to be explicitly reminded about that. I really wish that many Cargo subcommands were much quieter by default – cargo test is probably the worst offender as even its "quiet mode" prints several lines per crate tested, including the silliness of "Ran 0 tests, 0 successful, 0 failed, 0 ignored".
I was a bit facetious there. I actually appreciate cargo showing me what's happening because some compiles can take a bit of time and it's good to know that it's making progress and to have a reminder what I'm currently executing (e.g. I can't remember which project release profiles I have configured with debuginfo and which not). And sometimes I do have a "oops, I should be running release" moment.
Some things could be made less noisy, e.g. by using raw terminal features and deleting the crate lines once they're done. Make it more like a progress bar.
The closest to a sensible answer I can figure is something like gits notices, where it prints a big fat message along with instructions on how to stop showing it. But even if that were added, a "hey this will be slower than a release build" still doesn't seem like it would actually be a good idea, just a bad out of the box experience that everyone complains about.