I have the following code:
let counter n =
let rec count i =
if i > n
then ()
else
print_int i;
count (i+1)
in count 0
It should simply output all numbers from 0 to n. To clarify, I know there are easier ways to achieve the same result but I want to know why it is not working in this specific case.
When I run this code with some parameter eg. counter 5 it does not terminate.
Instead when I change the last line of my code in count 0 to in Thread.create count 0 it outputs 012345
Can someone explain this behaviour?
EDIT
Also found that if you modify the code to this:
let counter n =
let rec count i =
if i > n
then ()
else
let i = i
in print_int i;
count (i+1)
in count 0
it works fine. Why is this?
Your indentation is misleading; your code does
if i > n then () else print_int i;
first and then
count (i+1)
Of course it doesn't terminate! What you want is
else begin
print_int i;
count (i+1)
end
(or else ( ... )). See e.g. "Using begin ... end" in https://ocaml.org/learn/tutorials/if_statements_loops_and_recursion.html.
Related
I was asked this question in an interview:
Given a string (1<=|s|<=10^5), check if it is possible to partition it into three palindromes. If there are multiple answers possible, output the one where the cuts are made the earliest. If no answer is possible, print "Impossible".
**Input:**
radarnoonlevel
aabab
abcdefg
**Output:**
radar noon level
a a bab (Notice how a, aba, b is also an answer, but we will output the one with the earliest cuts)
Impossible
I was able to give a brute force solution, running two loops and checking palindrome property for every 3 substrings ( 0-i, i-j, j-end). This was obviously not optimal, but I have not been able to find a better solution since then.
I need a way of checking that if I know the palindrome property of a string, then how removing a character from the start or adding one at the end can give me the property of the new string without having to do the check for the whole string again. I am thinking of using three maps where each character key is mapped to number of occurences but that too doesn't lead me down anything.
Still O(n^2) solution, but you can store the result of palindrome substrings in a table and use that to get to the answer.
vector<string> threePalindromicSubstrings(string word) {
int n = word.size();
vector<vector<bool>> dp (n,vector<bool>(n,false));
for(int i = 0 ; i < n ; ++i)
dp[i][i] = 1;
for(int l = 2 ; l <= n ; ++l){
for(int i = 0 ; i < n - l +1 ; ++i){
int j = i + l - 1;
if(l == 2)
dp[i][j] = (word[i] == word[j]);
else
dp[i][j] = (word[i] == word[j]) && (dp[i+1][j-1]);
}
}
vector<string> ans;
for(int i = 0 ; i < n - 2 ; ++i){
if(dp[0][i]) {
for(int j = i+1 ; j < n - 1 ; ++j){
if(dp[i+1][j] && dp[j+1][n-1]){
ans.push_back(word.substr(0,i + 1));
ans.push_back(word.substr(i+1,j-i));
ans.push_back(word.substr(j+1,n-j));
return ans;
}
}
}
}
if(ans.empty())
ans.push_back("Impossible");
return ans;
}
I want to read a line from a file, initialize an array from that line and then display the integers.
Why is is not reading the five integers in the line? I want to get output 1 2 3 4 5, i have 1 1 1 1 1
open Array;;
open Scanf;;
let print_ints file_name =
let file = open_in file_name in
let s = input_line(file) in
let n = ref 5 in
let arr = Array.init !n (fun i -> if i < !n then sscanf s "%d" (fun a -> a) else 0) in
let i = ref 0 in
while !i < !n do
print_int (Array.get arr !i);
print_string " ";
i := !i + 1;
done;;
print_ints "string_ints.txt";;
My file is just: 1 2 3 4 5
You might want to try the following approach. Split your string into a list of substrings representing numbers. This answer describes one way of doing so. Then use the resulting function in your print_ints function.
let ints_of_string s =
List.map int_of_string (Str.split (Str.regexp " +") s)
let print_ints file_name =
let file = open_in file_name in
let s = input_line file in
let ints = ints_of_string s in
List.iter (fun i -> print_int i; print_char ' ') ints;
close_in file
let _ = print_ints "string_ints.txt"
When compiling, pass str.cma or str.cmxa as an argument (see this answer for details on compilation):
$ ocamlc str.cma print_ints.ml
Another alternative would be using the Scanf.bscanf function -- this question, contains an example (use with caution).
The Scanf.sscanf function may not be particularly suitable for this task.
An excerpt from the OCaml manual:
the scanf facility is not intended for heavy duty lexical analysis and parsing. If it appears not expressive enough for your needs, several alternative exists: regular expressions (module Str), stream parsers, ocamllex-generated lexers, ocamlyacc-generated parsers
There is though a way to parse a string of ints using Scanf.sscanf (which I wouldn't recommend):
let rec int_list_of_string s =
try
Scanf.sscanf s
"%d %[0-9-+ ]"
(fun n rest_str -> n :: int_list_of_string rest_str)
with
| End_of_file | Scanf.Scan_failure _ -> []
The trick here is to represent the input string s as a part which is going to be parsed into a an integer (%d) and the rest of the string using the range format: %[0-9-+ ]", which will match the rest of the string, containing only decimal digits 0-9, the - and + signs, and whitespace .
let len = 25000000
let map = Map.ofArray[|for i =1 to len do yield (i,i+1)|]
let maparr = [|map;map;map;map|]
let f1 i =
for i1 =1 to len do
let l1 = maparr.[i-1].Item(i1)
()
let index = [|1..4|]
let _ = index |> Array.Parallel.map f1
printf "done"
I found that only one core is working at full speed be the code above . But what i except is all the four thread is working together with a high level of cpu usage. So it seems multithread conflict with Map, am i right? If not, how can achieve my initial goal? Thank you in advance
So I think you were tripping a heuristic where the library assumed when there were only a small number of tasks, it would be fastest to just use a single thread.
This code maxes out all threads on my computer:
let len = 1000000
let map = Map.ofArray[|for i =1 to len do yield (i,i+1)|]
let maparr = [|map;map;map;map|]
let f1 (m:Map<_,_>) =
let mutable sum = 0
for i1 =1 to len do
let l1 = m.Item(i1)
for i = 1 to 10000 do
sum <- sum + 1
printfn "%i" sum
let index = [|1..40|]
printfn "starting"
index |> Array.map (fun t -> maparr.[(t-1)/10]) |> Array.Parallel.iter f1
printf "done"
Important changes:
Reduced len significantly. In your code, almost all the time was spent creating the matrix.
Actually do work in the loop. In your code, it is possible that the loop was optimised to a no-op.
Run many more tasks. This tricked the scheduler into using more threads and all is good
I've got this legacy code I'm analyzing:
If (X) then
if Cnt < 4 then Cnt = Cnt + 1 ; 4 samples
Else
if Cnt > 0 then Cnt = Cnt-1 ; keep history
EndIf
Which has Cnt go up and down depending on X
And I'm wondering if that else statement acts like their indention implies they think it does.
The code might be interpreted more like:
If (X) then
if Cnt < 4 then
Cnt = Cnt + 1 ; 4 samples
Else
if Cnt > 0 then
Cnt = Cnt-1 ; keep history
EndIf
In which Cnt get to 4 and then toggles on/off if X is true.
This is basic as compiled using BCI51. That's a basic compiler for an 8051 from back in 1990 by Systronix.
How do nested if-else pairs get resolved in basic?
I remember how QBasic did so, and I'm going to assume that this complier is doing the same. This is really tugging on my memory, so I might be wrong.
If a IF THEN is followed by code on the same line, then it is fully contained. Therefore
if Cnt < 4 then Cnt = Cnt + 1
else
...
would be illegal and you must place the Cnt = Cnt + 1 on it's own line to create a multi-line IF statement. Therefore, the ELSE is paired the topmost IF
Since, in the original code, the Cnt = Cnt + 1 and Cnt = Cnt - 1 are on the same lines as the IF THEN, I would interpret the code as follows:
If (X) then
If Cnt < 4 Then
Cnt = Cnt + 1 ; 4 samples
EndIf
Else
If Cnt > 0 Then
Cnt = Cnt-1 ; keep history
EndIf
EndIf
So, yes, I believe the code operates as the indentation implies.
Are you able to modify the code and test if you see any changes?
In section2.2,a problem called"subset sum"require you to calculate in how many ways can a integer set from 1 to n be partitioned into two sets whose sums are identical.
I know the recurrence is:
f[i][j] : numbers of ways that sum up to j with 1...i
f[i][j]=f[i-1][j]+f[i-1][j-i]
if the initial condition is:
f[1][1]=1;//others are all zero,main loop start from 2
OR:
f[0][0]=1;//others are all zero,main loop start from 1
the answers are all f[n][n*(n+1)/4].Does this means the initial condition doesn't affect the answer?
but if I use a one dimension array,say f[N]:
let f[0]=1,loop from 1(so f[0] is f[0][0] in fact),the answer is f[n]/2
or f[1]=1,loop from 2(f[1] is f[1][1]),the answer is f[n]
I am so confused...
I don't know if you are still stuck on this problem, but here's a solution for anyone else who stumbles onto this problem.
Let ways[i] be the number of ways you can get a sum of i using a subset of the numbers 1...N.
Then it becomes a variant of the 0-1 knapsack algorithm:
base case: ways[0] = 1
for (int i = 1; i <= N; i++) {
for (int j = sum - i; j >= 0; --j) { //sum is n*(n+1)/2
ways[j + i] += ways[j];
}
}
Your answer is located at ways[sum/2]/2.