So, I just started out with Kotlin and tried to solve "min steps for a knight to reach a destination on a chessboard" problem.
Here is my code:
fun knightSteps(i:Int,j:Int,a:Int,b:Int,board:Int,c :Int,d:Int,visited : MutableList<Pair<Int,Int>>,steps:Int):Int{
// (i,j) start (a,b)knight moves (c,d) destination visited - visited positions board - size of board
if(i==c && j==d) return steps
if(isValid(Pair(i,j),board)){
val v = visited
v.add(Pair(i,j))
var possible = mutableListOf<Int>()
if(Pair(i+a,j+b) !in v ) {
possible.add(knightSteps(i + a, j + b, a, b, board,c,d, v, 1 + steps))
}
if(Pair(i+a,j-b) !in v ) {
if(i==1&&j==3) println("YES!!")
possible.add(knightSteps(i + a, j - b, a, b, board,c,d, v, 1 + steps))
}
.
. // rest of other 8 possible moves
.
possible.removeAll{it==-1}
if(possible.size==0){
return -1
}
//println(possible)
return possible.min()!!
}
return -1
}
But once it passes the first 'if' condition the 'visited' and 'v' mutable lists are changing their values as a result the println("YES!!") in second 'if' is never executed.
So the function is changing them.. again if i change val v = visited.toMutableList() it enters into infinite loop! Can someone help.
Yes, in java and kotlin almost everything is being passed as reference. But in kotlin you have compile-time verified ability to make any MutableList immutable - just change method argument type from MutableList to List
When you add values to visited they will be added to the argument of your function (i.e. are also visible outside the function). Also, v and visited are pointing to the same object. It doesn't matter which variable you use to add elements to, the list will contain a new element afterwards. The statement val v = visited does not create any copy.
For copying a list you can do visited.toList() which under the hood basically maps to a call of ArrayList(visited).
Related
In the following for loop, I test if a letter in a query is in an unordered_map<string, int>. If it is not, I print out some things.
queries = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ]
for (vector<string>& q : queries) {
int start = index[q[0]], end = index[q[1]];
if (index.find("z") == index.end()) {cout << "z" << '\n';
}
index only contains a, b, c. Correspondingly, the output is this:
z
z
z
z
z
Which it should be, because one of the queries has an z in it. Printing the size of index gives 3.
However, if I run this:
for (vector<string>& q : queries) {
int start = index[q[0]], end = index[q[1]];
if (index.find(q[0]) == index.end()) {cout << "z" << '\n';
}
I don't get any output, but I expect output for x because that isn't in index.
Why is this?
By the description of the operator [] of map in cppreferance:
Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.
index[q[0]] created the entry of the key "x".
The operator[] for a std::(unordered_)map creates a new entry in the map if the requested key is not found.
index only contains a, b, c.
In your first example, index.find("z") will return index.end() if q[0] and q[1] are never "z", which is true in your example.
However, by the time your loop finishes, index will not contain just a, b, c like you think. It will actually contain a, b, c, e, x. When you initialize start and end with the values of index[q[0]] and index[q[1]], the operator[] will insert the values of q[0] and q[1] into index if they do not already exist.
I don't get any output, but I expect output for x because that isn't in index.
In your second example, index.find(q[0]) will never return index.end(), because of initializing start and end with the values of index[q[0]] and index[q[1]]. Every value in q[0] and q[1] gets added into index. So, adding the value of q[0] and then searching for the value of q[0] will always succeed, and never return index.end().
So yes, there actually IS an entry for "x" in index, when the loop reaches the last vector in queries containing "x" strings and the operator[] adds them into index.
I need to make an union of two unordered multisets passed from input, by using the "multiplicity" definition: The multiplicity of an element, also called absolute frequency, is the number of occurrences of the element 'x' in the unordered multiset 's'.
In the multiSetUnion the multiplicity of an element is the Max of its multiplicity in the two multisets.
I already implemented correctly the int multiplicity(const Elem e, const MultiSet& s) function (returns number of occurrences in the multiset).
The multisets are singly linked lists.
Here is the algorithm I came up with:
for as long as the first list isn't empty
if elem of the first list (multiset) is not in the second list (multiset)
add elem in unionlist
if elem of the first list (multiset) is in the second list (multiset)
if multiplicity of elem is bigger in the first list than in the second one
add elem in unionlist as many times as its multiplicity in list1
if multiplicity of elem is bigger in the second list than in the first one
add elem in unionlist as many times as its multiplicity in list2
analyze the second element of the first list
Here is my implementation of my algorithm, but it gives me errors when neither of the two lists are empty and I have no idea why:
MultiSet multiset::multiSetUnion(const MultiSet& s1, const MultiSet& s2)
{
if (isEmpty(s1) && isEmpty(s2))
return emptySet;
if (isEmpty(s1) && !isEmpty(s2))
return s2;
if (!isEmpty(s1) && isEmpty(s2))
return s1;
MultiSet s3 = emptySet;
MultiSet aux2 = s2; //THE FUNCTION DOESN'T WORK FROM HERE ON
for (MultiSet aux1 = s1; !isEmpty(aux1); aux1 = aux1->next) {
if (!isIn(aux1->elem, aux2))
insertElemS(aux1->elem, s3);
if (isIn(aux1->elem, aux2)) {
if (multiplicity(aux1->elem, aux1) > multiplicity(aux1->elem, aux2)) {
for (int n = 0; n < multiplicity(aux1->elem, aux1); ++n)
insertElemS(aux1->elem, s3);
}
else {
for (int m = 0; m < multiplicity(aux1->elem, aux2); ++m)
insertElemS(aux1->elem, s3);
}
}
}
return s3;
}
Could anybody please point out where am I doing wrong? Did I forget something in the algorithm or is this an implementation problem?
Edit: Here is how I have implemented the functions IsIn(const Elem x, MultiSet& s) and multiplicity(const Elem e, MultiSet& s):
bool isIn(const Elem x, MultiSet& s) {
if (s->elem == x) return true;
while (!isEmpty(s)) {
if (s->elem!=x)
s = s->next;
else return true;
}
return false;
}
int multiset::multiplicity(const Elem e, const MultiSet& s)
{
if (isEmpty(s)) return 0;
int count = 0;
MultiSet aux = s;
while (!isEmpty(aux)) {
if (aux->elem==e) {
++count;
}
aux = aux->next;
}
return count;
}
Unfortunately I cannot use the vector library (or any STL library for the matter).
The algorithm I proposed is the intentionally half of the solution (the part I'm having problems with).
I am not getting any specific errors but the program simply stalls (it should instead print the first, the second and the union of the two multisets - the print function is correct and is called directly in the main; as for now I only get the correct output when one or both of the multisets is empty) and returns this: "Process returned -1073741819" (I am currently debugging on Windows).
Consider the following example:
MultiSet s1({7, 7});
MultiSet s2({5});
If you now iterate over s1:
1st iteration: 7 7
^
aux1
2nd iteration: 7 7
^
aux1
If you have multiple equal elements in s1, you will discover them more than once, finally resulting in adding the square of multiplicity (or product of both multiplicities, if the one of s2 is greater).
On the other hand, as 5 is not contained in s1, you won't try to look it up in s2 either – still, it is there...
To fix the first problem, you need to check, if the current element is already contained in s3 and if so, just skip it.
To fix the second problem, you need to iterate over s2, too, adding all those elements that are not yet contained in s3.
As is, the final result will be of pretty poor performance, though (should be somewhere in between O(n²) and O(n³), rather the latter). Unfortunately, you chose a data structure (a simple singly linked list – apparently unsorted!) that offers poor support for the operations you intend – and especially for the algorithm you chose.
If you kept your two lists sorted, you could create an algorithm with linear run-time. It would work similarly as the merging step in merge sort:
while(elements available in both lists):
if(left element < right element):
append left element to s3
advance left
else
append right element to s3
if(left element == right element):
advance left // (too! -> avoid inserting sum of multiplicities)
advance right
append all elements remaining in left
append all elements remaining in right
// actually, only in one of left and right, there can be elements left
// but you don't know in which one...
Keeping your list sorted during insertions is pretty simple:
while(current element < new element):
advance
insert before current element // (or at end, if no current left any more)
However, as you expose the nodes of the list directly, you are always in danger that insertion will not start at the head element – and your sorting order might get broken.
You should encapsulate appropriately:
Rename your current MultiSet to e. g. 'Node' and create a new class MultiSet.
Make the node class a nested class of the new set class.
All modifiers of the list should be members of the set class only.
You might expose the node class, but user must not be able to modify it. It would then just serve as kind of iterator.
In the following code, I have tried using a field variable (of class or record) or an array element directly as a loop counter, but this was illegal ("error: invalid index expression"). Is this simply because the loop counter must be a scalar variable?
class Cls {
var n: int;
}
proc main()
{
var x = new Cls( 100 );
var k: [1..10] int;
for x.n in 1..3 do // error: invalid index expression
writeln( x.n );
for k[1] in 1..3 do // error: invalid index expression
writeln( k[1] );
}
On the other hand, if I create a reference to x.n, it compiled successfully but x in the outer scope was not modified. Is this because a new loop variable named n is created in the for-loop? (which I'm afraid is almost the same as my another question...)
proc main()
{
var x = new Cls( 100 );
ref n = x.n;
for n in 1..3 do
writeln( n );
writeln( "x = ", x ); // x = {n = 100}
}
If a loop variable is created independently, I guess something like "var x.n = ..." might happen (internally) if I write for x.n in 1..3, which seems really invalid (because it means that I'm trying to declare a loop variable with a name x.n).
You're correct that this relates to your other question. As described there, Chapel's for-loops create new index variables to store the values yielded by the iterator expression(s), so a loop like for i in ... results in a new variable i being declared rather than using an existing variable or expression. If you think the error message should be improved to make this clearer, please consider suggesting a new wording in a GitHub issue.
Note that in addition to single variable names, a loop can also use tuples of index variables to capture the results of a zippered iteration or an iterand that yields tuple values. For instance, the values of the following zippered iteration can either be captured as scalar values i and j:
for (i,j) in zip(1..3, 2..6 by 2) do // store values in 'i' and 'j' respectively
writeln((i,j));
or as a single variable of tuple type:
for ij in zip(1..3, 2..6 by 2) do // store values in 2-tuple 'ij'
writeln(ij);
Similarly, when iterating over something that yields tuple values, such as a multidimensional index set, the results can be captured either as scalar values or tuples:
const D = {1..3, 0..2}; // declare a 2D rectangular domain
for (i,j) in D do // store indices in new scalars 'i' and 'j'
writeln((i,j));
for ij in D do // store indices in new 2-tuple 'ij'
writeln(ij);
More complex iterators that return larger, or nested tuples, can similarly be de-tupled or not in the declaration of the index variable(s).
I have a list of elements as a macro, and I would like to generate a macro that contains all possible pairs of these elements, separated by an ampersand. For example, with three elements az, by and cx:
local elementList az by cx
I would like to dynamically generate a macro pairList containing:
az&by az&cx by&cx
(The order of the two elements within a pair should not matter, so that either az&by or by&az should be in pairList but not both.)
It sounds fairly simple but I'm not sure how to do it elegantly. (In my case I have around ten elements to start with.)
I agree with Nick's recommendation of tuples for this task. The example below suggests a slightly more elegant version of the approach you gave.
local elementList a b c d e f g h i j k l
local pairList // initialize the list of pairs
local seenList // initialize the list of elements already seen
foreach first of local elementList {
foreach second of local seenList {
local pairList `pairList' `second'&`first'
}
local seenList `seenList' `first'
}
display "List of unique pairs: `pairList'"
I wasn't sure how to use a recursive algorithm like I found on other S.O. threads, so here is my "brute force" approach. Definitely not the most elegant but does th the job:
local elementList a b c d e f g h i j k l
local pairList // initialize the list of pairs
foreach first in `elementList' {
foreach second in `elementList' {
// only do something if the elements are not the same
if("`first'" != "`second'") {
local pair `first'&`second' // pair
local pairReverse `second'&`first' // pair in reverse order
// if pair (or its inverse) is not already in the list, add the pair
if(strpos("`pairList'","`pair'") == 0 & strpos("`pairList'","`pairReverse'") == 0 ) {
local pairList `pairList' `pair'
}
}
} // end of loop on second element
} // end of loop on first element
display "List of unique pairs: `pairList'"
So I want to create a subset, run that subset through code, then create a new subset. I'm using a vector for the set and subset. So far I have 3 nested for loops but I'm having trouble figuring out the variables I need.
Here's what I want to do. set = {0, 1, 2, 3, 4, 5} the value matches the index just to simplify this example. I now want subset = {} -> {0} -> {1} -> ... -> {0,1} -> {0,2} -> ... -> {0,5} -> {0,1,2} -> ... -> {0,4,5}. I'm having trouble representing the conditions in terms of variables.
Basically I want the first for loop to increase the subset size. from 0 to set.size() (this is easy). Within that loop, I want to have an iterator corresponding to the index in the element of the subset. I have this iterator initialized to subset.size(), so that we work with the last element first, then work our way to the first element in the subset. then the 3rd for loop, I want to iterate between possible values from the set. Let's say our current subset = {0,1,2} how do I let my program know to put the value '2' inside the last element of the subset, then 1 then 0?
I'm thinking it would involve something with taking the difference from set.size()-1 and subset.size()-1? But I'm not quite sure how. so then I want to iterate through until {0,1,5} and then {0,4,5} but again I'm not sure how to tell the program to stop at 4, as opposed to 5. Again I think this is something with difference but I can't quite figure it out.
to recap:
for loop to iterate through subset size
for loop to iterate through subset "working" element, starting from back
for loop to iterate through that index of subset,
starting from the correct corresponding set value to ending
at the correct corresponding set value
such that the subset goes from {} -> {0} -> {1} ->...-> {0,1} -> {4,5} -> {1,2,3} -> ... -> {1,4,5} and I dont actually need subset = {1,2,3,4,5} but it doesn't hurt my code if I can't stop before that. Again I'm looking to represent the start and end points as variables to make the inner loops work, but I can't figure it out. Huge thanks to anyone who can help me out.
this is approximately how I would go about it.
//handle null subset
for ( int size = 1; size < n; i++ ) {
int indices[size];
for ( int i = 0; i < size; i++ ) indices[i] = i;
while ( indices[0] <= n - size ) {
int i;
for ( i = 1; indices[size - i] == n - i; i-- );
indices[i]++;
for ( i = i + 1; i < size; i++ ) indices[i] = indices[i-1] + 1;
//print out elems using the indices in `indices`
}
//done with all subsets of size `size`
}
The outer loop should be pretty self explanatory. Including 0 seemed like it was going to make some of the inner logic annoying so I started at subsets of size 1.
indices holds the indices of the elements that should be included in the current subset. It starts with the indices 0-size-1.
The condition for the while isn't exactly obvious. The last valid subset this generates contains the last size elements, so if the first index is past n - size we've gone too far.
The inside of the while loop is just incrementing the subset. It looks for the last element that can be incremented and still give a valid subset, increments it, and then resets all of the subsequent elements to be as small as possible. Then you print it out somehow.
And that should be close to something that will do what you want. Let me know if it needs clarifications or corrections.
A trick to enumerate all subsets is to permutate a "selection flag" array, each element of which indicates whether corresponding element in original array is selected.
following is sample code:
void foo(const vector<int>& a)
{
size_t size = a.size();
// selection flag array
// '1' indicates selected, '0' indicates unselected
vector<int> f(size, 0);
for (size_t i = 1; i <= size; i++)
{
// increase the count of selected elements
f[i - 1] = 1;
do
{
for (size_t i = 0; i < size; i++)
{
if (f[i])
{
printf("%d\t", a[i]);
}
}
printf("\n");
} while (next_permutation(f.begin(), f.end(), [](int a, int b){ return a > b; }));
// next_permutation tries to permutate the array
// i.e. '1 1 0 0' -> '1 0 1 0' -> '0 1 1 0' -> ... -> '0 0 1 1'(end)
}
}