The game is that you have N piles of stones, on each player's turn he must remove at least 1 stone from a pile, and the player who removes the last stone loses.
I wrote out the winner in a dozen or so cases starting with the base case
/*
stones | winner | N | ones
========================================
{1} | Second | 1 | 1
{i}, i>1 | First | 1 | 0
{1,1} | First | 2 | 2
{1,i}, i>1 | First | 2 | 1
{i,j}, i,j>1 | Second | 2 | 0
{1,1,1} | Second | 3 | 3
{1,1,i}, i>1 | First | 3 | 2
{1,i,j}, i,j>1 | First | 3 | 1
{i,j,k}, i,j,k>1 | First | 3 | 0
{1,1,1,1} | First | 4 | 4
{1,1,1,i} | First | 4 | 3
{1,1,i,j}, i,j>1 | Second | 4 | 2
{1,i,j,k}, i,j,k>1 | First | 4 | 1
{i,j,k,m}, ... | Second | 4 | 0
*/
and from that I think I deduced a formula
static string GetWinner(int[] piles)
{
int n = piles.Length, m = piles.Count(stones => stones == 1);
if(m == n) // one stone per pile
return n % 2 == 0 ? "First" : "Second";
// if here, m < n
return n % 2 == 0 ? (m % 2 == 0 ? "Second" : "First") : "First";
}
but this is failing the test case {2,1,3} which should result in "Second".
I try to use the following fact.
Any number of stones in a pile that is greater than 2 would give the same results if it were 2. The reason is because if it's greater than 2 and the player doesn't shrink the pile to 1 on that turn then the player has basically give his opponent the turn.
However, there might be something I'm wrong about ..
I think your following statement is off:
Any number of stones in a pile that is greater than 2 would give the same results if it were 2
If the state is {1,2,2} The first player can win by removing the 1 stone. If the state is {1,2,3} the first player cannot win. So there is a difference between if the number of stones is 2 or 3.
because if it's greater than 2 and the player doesn't shrink the pile to 1 on that turn then the player has basically give his opponent the turn.
This is correct, except that it is sometimes 'desirable' to give the turn to the other player, i.e. passing the turn.
The optimal strategy has to do with the XOR of the number of items in each pile in binary representation. See https://en.wikipedia.org/wiki/Nim for the optimal solution and details.
I can not deeply understand the math behind the answer, but after some research and optimisation, this is the solution I came up with for python3:
from functools import reduce
def misereNim(s):
if(max(s)==1):
return "First" if (len(s) % 2 ==0) else "Second"
else:
xor = reduce((lambda x, y: x ^ y), s)
return "Second" if xor == 0 else "First"
if __name__ == '__main__':
s = [9, 8, 4, 4, 4, 7]
result = misereNim(s)
print(result)
Related
I have a sorted array of objects that contains 3 doubles, lets call them x, y and z. I need to create an array of indexes for each transition point, example:
index x y z
------------------
0 | 3 | 2 | 1
1 | 4 | 3 | 1
2 | 3 | 1 | 1
3 | 1 | 3 | 2
4 | 3 | 1 | 2
5 | 1 | 3 | 3
6 | 1 | 3 | 3
Should give me the array {3,5} as that is the point where z changes, I have tried
var ans = myObjectArr.Select(a => a.z).Distinct().ToList();but that simply gives me a list of the values themselves and not the index they are in the object array. The array is very large and i would like to avoid iterating my way through it discreetly. I feel like i'm just missing something silly and any help would be appreciated. Generating a list or an array would both be acceptable.
EDIT: I was under the impression that using Linq was faster than doing it iteratively, after reading comments i find this not to be the case and because of this Charlieface's answer is the best one for my problem.
var lastZ = myObjectArr[0].z;
var zIndexes = new List<int>();
for(var i = 1; i < myObjectArr.Length; i++)
{
if(myObjectArr[i] != lastZ)
{
lastZ = myObjectArr[i];
zIndexes.Add(i);
}
}
// or you can use obscure Linq code if it makes you feel better
var zIndexes = myObjectArr
.Select((o, i) => (o, i))
.Skip(1)
.Aggregate(
new List<int>(),
(list, tuple) => {
if(tuple.o.z != lastZ)
{
lastZ = tuple.o.z;
list.Add(tuple.i);
}
return list;
} );
I have a table for employees evaluations records which is related to another table that holds the evaluations subjects, it has 3 types of evaluations like:
Negative & Positive (represented as integer value in table "-3, -2" respectively).
No & Yes (represented as integer value in table "-1, 0" respectively).
value from 1 to 5 (represented as integer with same value).
So this is an example of the table design:
--------------------
| evaID | int |
--------------------
| employeeID | int |
--------------------
| evaRec | int |
--------------------
and this is example of the table data:
-------------------------------
| evaID | employeeID | evaRec |
-------------------------------
| 1 | 00001 | -3 |
-------------------------------
| 17 | 00001 | -2 |
-------------------------------
| 19 | 00001 | -2 |
-------------------------------
| 19 | 00001 | -1 |
-------------------------------
| 16 | 00002 | 3 |
-------------------------------
| 16 | 00005 | 0 |
-------------------------------
Now what I want is to select the sum of all records for specific employee as a percentage of the evaluations according to types but with separation of the 3 types like for ex (not related to that table data):
Negative and Positive type: 20% / 80%
No & Yes type: 30% / 70%
1,2,3,4 or 5 type: 10% / 50% / 5% / 15% / 20%
So basically I want the select statement to return 6 float values represents the percentage of all the previous mentioned types as (floatNegative, floatNo, float1, float2 float3 and float4) and if possible - but I know it's hard because I can't figure out the logic behind it yet - I want it to return a 7th float value represents a percentage for all like bad vs good evaluation but I can't figure out yet how to mix the "Yes or No" which is 2 factor percentage, with the "1,2,3,4 or 5" which is 5 factors percentage!
So later in my c# code I will use the select results like:
floatNegative = 20 (Negative = 20% and Positive = 100-floatNegative = 80%)
floattNo = 30 (No = 30% and Yes= 100-floatNo = 70%)
and so on with the 5 other numbers...
That means I have 3 separate groups of percentages calculations according to evaluation types mentioned above.
So finally if I run the query over employee "00001" from table above I'd get the resutls:
floatNegative = 33.3
floatPositive = 66.6
floatNo = 100.0
because he has 1 x "negative" record (-3) and 2 x "positive" records (-2) with a total of 3 records. (on "Negative/Positive" type group of evaluation), and also he has 1 x "no" record (-1) but hasn't any "yes" records (0) that's why the result is 100% for "No" (on "No/Yes" type group of evaluation). and I don't care for other types results if he hasn't any records for it (like 1,2,3,4,5) it could be negative float value so I can distinguish it on my c# code to figure out that he has no records yet on this types and hide the percentage indicator text on my asp.net final markup.
I think that you are looking for conditional aggregation. The logic is to GROUP BY employeeID, and then use various SUM(CASE ...) epressions to compute the intermediate sums.
Say you want to count negative evaluation of an employee, theu n :
SUM(CASE WHEN evaRec = -2 THEN 1 ELSE 0 END)
You also compute the total positive and negative feedbacks :
SUM(CASE WHEN evaRec IN (-2, -3) THEN 1 ELSE 0 END)
Here is a full query using that principles. For binaries evaluation type (Positive/Negative, Yes/No), only one of the two values is computed (the other is just 1 - <this_value>). For 1/2/3/4/5 types, each proportion is computed individualy.
SELECT
employeeID,
1.0 * SUM(CASE WHEN evaRec = -2 THEN 1 ELSE 0 END) / NULLIF(SUM(CASE WHEN evaRec IN (-2, -3) THEN 1 ELSE 0 END), 0) PercentPositive,
1.0 * SUM(CASE WHEN evaRec = 0 THEN 1 ELSE 0 END) / NULLIF(SUM(CASE WHEN evaRec IN (-1, 0) THEN 1 ELSE 0 END), 0) PercentYes,
1.0 * SUM(CASE WHEN evaRec = 1 THEN 1 ELSE 0 END) / NULLIF(SUM(CASE WHEN evaRec IN (1, 2, 3, 4, 5) THEN 1 ELSE 0 END), 0) PercentValue1,
1.0 * SUM(CASE WHEN evaRec = 2 THEN 1 ELSE 0 END) / NULLIF(SUM(CASE WHEN evaRec IN (1, 2, 3, 4, 5) THEN 1 ELSE 0 END), 0) PercentValue2,
1.0 * SUM(CASE WHEN evaRec = 3 THEN 1 ELSE 0 END) / NULLIF(SUM(CASE WHEN evaRec IN (1, 2, 3, 4, 5) THEN 1 ELSE 0 END), 0) PercentValue3,
1.0 * SUM(CASE WHEN evaRec = 4 THEN 1 ELSE 0 END) / NULLIF(SUM(CASE WHEN evaRec IN (1, 2, 3, 4, 5) THEN 1 ELSE 0 END), 0) PercentValue4,
1.0 * SUM(CASE WHEN evaRec = 5 THEN 1 ELSE 0 END) / NULLIF(SUM(CASE WHEN evaRec IN (1, 2, 3, 4, 5) THEN 1 ELSE 0 END), 0) PercentValue5
FROM t
GROUP BY employeeID
NB : special care need to be taken to avoid division by 0.
This DB Fiddle with your sample data returns :
employeeID | PercentPositive | PercentYes | PercentValue1 | PercentValue2 | PercentValue3 | PercentValue4 | PercentValue5
---------: | :-------------- | :------------- | :------------- | :------------- | :------------- | :------------- | :-------------
1 | 0.666666666666 | 0.000000000000 | null | null | null | null | null
2 | null | null | 0.000000000000 | 0.000000000000 | 1.000000000000 | 0.000000000000 | 0.000000000000
5 | null | 1.000000000000 | null | null | null | null | null
This is almost an impossible question to ask, but any advice on the algorithm would be greatly appreciated (I will explain the best I can);
I have an array of size ~4000 bytes which contains data in byte format.
For this demonstration, I am going to simplify things a bit; say it's size 7 (to represent 'blocks' of data, not single values!);
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |
I am adding a value at position 0, with the reset of the array being '0'
key: N = newest, O = oldest, X = Filled
| N | | | | | | |
I now need to add another value. this will be entered at the next available position.
| O | N | | | | | |
So now position [0] is now the 'oldest' part of the array, and position [1] is the newest.
This has been (currently) worked out by looking all the way right, seeing no values, and then starting from position [0] until it sees a value.
Let's add another:
| O | X | N | | | | |
Note, the oldest value hasn't changed position, as it is still the oldest part of the array.
I am now going to 'clear' the oldest part of the array (in this example it is currently pos [0]). this makes 'O' move over to the next position.
| | O | N | | | | |
Lets add another value. Since it will go to the first 'empty' space, it will go to position [0]; this means the first position is now at position [0].
| N | O | X | | | | |
I'm going to clear another one now; so again, by looking from the right of the newest value, I see a value is at position 1. So i'm going to clear it.
| | | O/N | | | | |
this means position [2] is now both the newest and oldest value available.
Adding another makes;
| N | | O | | | | |
Adding another;
| X | N | O | | | | |
and adding another;
| X | X | O | N | | | |
I am looking to delete the oldest value now. So by looking right from position of the 'newest' variable, I see pos[0] has a value, so that must be it. UH-OH that's not the oldest value!
As you can (hopefully) tell, I am unable to get the oldest ticket by looking to the right for my next value - this problem only occurs every so often, and has been hard to find a solution.
I only know the index of the most recent value added, and this is very hard to find a solution. (lots of scribbliing and diagrams have been attempted, lots of scrumpled up paper).
So if anyone had any ideas as to how I could ALWAYS find the oldest value's index, I would be greatly appreciative! (I also know this is quite a complex question, so if anyone wants/needs clarification, I'll be happy to edit/explain further!) I have tagged c#, but realistically I only need a BASIC algorithm for any progress to be honest!!!
====================================================================================
EDIT
Answers have suggested to allocate to the right of the 'newest' position;
like:
| | | O | N | | | |
| | | O | X | N | | |
| | | O | X | X | N | |
| | | O | X | X | X | N |
| N | | O | X | X | X | X |
| X | N | O | X | X | X | X |
Which I think COULD work, but anyone know if this would fail (say, I removed a value at a certain time/etc?)
I guess you are forced to use an array; if not then you should consider switching to an adequate data structure such as a Queue.
If you are indeed forced to use an array, and can only keep a pointer to the latest block, then i would recommend always adding new blocks the to the right of the latest block, with a index wrapping back to zero at array size.
This lets you determine what the oldest block is by looking to the blocks right of the latest block, until you find a non empty block: this is your oldest block. Null it to remove it from the array and carry on :)
Let's illustrate:
| N | | | | | | | // newBlockIndex at 0, adding, newBlockIndex becomes 1
| X | N | | | | | | // newBlockIndex at 1, adding, newBlockIndex becomes 2
| X | X | N | | | | | // newBlockIndex at 2, adding, newBlockIndex becomes 3
| | X | N | | | | | // newBlockIndex at 3, removing, no item before index 0, we delete it
| | X | X | N | | | | // newBlockIndex at 3, adding, newBlockIndex becomes 4
...
EDIT TO ADD
Regarding your edit, I think the mechanism is quite robust. Even if you were to remove an item (any item, even the latest one) by error, the next operation can succeed because latest and newest are defined in regards to their position to the current index. Newest item is the first on the left of the index, oldest the first on the right.
Even if you don't check for your array size and fill it completely (which I don't recommend, though), the algorithm will overwrite the oldest item with the newest: it may not be good but it is coherent with the notion of a queue. Of course if the array fills up you can always decide to allocate a new one larger and copy the current one to the larger array
What you are looking for is a queue data structure.
Queues can be conveniently implemented with a circular buffer where you have a head index and a tail index.
Head and Tail are both initially set to zero.
Add a new element by writing it to where Tail points, then increment Tail. Wrap as needed if incrementing makes it go off the end of the array.
Delete an old element by incrementing Head. Again, wrap as needed if incrementing makes it go off the end of the array.
Head always points at the oldest element.
Tail always points to the right of the newest element.
Use a System.Collections.Generic.Queue<T>, where T is a byte block.
Queue<byte[]> queue = new Queue<byte[]>();
byte[] block;
queue.Enqueue(new byte[] { 10, 11, 12, 13 });
queue.Enqueue(new byte[] { 20, 21, 22, 23 });
queue.Enqueue(new byte[] { 30, 31, 32, 33 });
block = queue.Dequeue();
queue.Enqueue(new byte[] { 40, 41, 42, 43 });
block = queue.Dequeue();
block = queue.Dequeue();
queue.Enqueue(new byte[] { 50, 51, 52, 53 });
queue.Enqueue(new byte[] { 60, 61, 62, 63 });
queue.Enqueue(new byte[] { 70, 71, 72, 73 });
block = queue.Dequeue();
// ...
Dequeue always removes the oldest element!
Since you have clarified in comments that it must be an array, here is a solution that encapsulates an array-queue in a class. It treats consecutive elements as data block of a defined size. It also allows you to access array elements by index and the array itself. This not typical for queues, but since you need the array...
public class ArrayBlocksQueue<T>
{
private T[] _array;
private int _in, _out, _count, _length, _blockSize;
public ArrayBlocksQueue(int maxBlocks, int blockSize)
{
_length = maxBlocks * blockSize;
_blockSize = blockSize;
_array = new T[_length];
}
public void Enqueue(params T[] block)
{
if (block == null) {
throw new ArgumentNullException();
}
if (block.Length != _blockSize) {
throw new ArgumentException("Data does not have required block size.");
}
if (_count + _blockSize > _length) {
throw new ApplicationException("Queue is full");
}
block.CopyTo(_array, _in);
_in = (_in + _blockSize) % _length;
_count += _blockSize;
}
public T[] Dequeue()
{
if (_count == 0) {
throw new ApplicationException("Queue is empty");
}
T[] temp = new T[_blockSize];
System.Array.Copy(_array, _out, temp, 0, _blockSize);
_out = (_out + _blockSize) % _length;
_count -= _blockSize;
return temp;
}
public int Count { get { return _count; } }
public int BlockCount { get { return _count / _blockSize; } }
public T[] Array { get { return _array; } }
public T this[int index]
{
get
{
if (!IsIndexValid(index)) {
throw new IndexOutOfRangeException();
}
return _array[index];
}
set
{
if (!IsIndexValid(index)) {
throw new IndexOutOfRangeException();
}
_array[index] = value;
}
}
public bool IsIndexValid(int index)
{
if (index < 0 || index >= _length) {
return false;
}
if (_count == _length) {
return true;
}
return _out > _in
? index < _in || index >= _out
: index >= _out && index < _in;
}
}
I have a list of object (with id) and a list int, what is the best way to query that list object provided the list int.
class CommonPartRecord {
public int Id {get;set;}
public object Others {get;set;}
}
var listObj = new List<CommonPartRecord>();
// Load listObj
var listId = new List<int>();
// Load listId
Now select the listObj, for those Id is contained in listId, I currently do this way:
var filterItems = listObj.Where(x => listId.Contains(x.Id));
What would be the faster way to perform this?
Thanks,
Huy
var tmpList = new HashSet<int>(listId);
var filterItems = listObj.Where(x => tmpList.Contains(x.Id));
This could give you a performance boost or a performance drop, it depends heavily on the size of both listObj and listId.
You will need to profile it to see if you get any improvement from it.
Explaining the boost or drop:
I am going to use some really exagrated numbers to make the math easier, lets say the following
listObj.Where(x => listId.Contains(x.Id)); takes 5 seconds per row.
listObj.Where(x => tmpList.Contains(x.Id)) takes 2 seconds per row.
var tmpList = new HashSet<int>(listId); takes 10 seconds to build.
Lets plot out the times of how long it would take to process the data varying by the number of rows in listObj
+----------------+------------------------------+----------------------------------+
| Number of rows | Seconds to process with list | Seconds to process with hash set |
+----------------+------------------------------+----------------------------------+
| 1 | 5 | 12 |
| 2 | 10 | 14 |
| 3 | 15 | 16 |
| 4 | 20 | 18 |
| 5 | 25 | 20 |
| 6 | 30 | 22 |
| 7 | 35 | 24 |
| 8 | 40 | 26 |
+----------------+------------------------------+----------------------------------+
So you can see if listObj has 1 to 3 rows your old way is faster, however once you have 4 rows or more the new way is faster.
(Note I totally made these numbers up, I can guarantee that the per row for HashSet is faster than per row for List, but I can not tell you how much faster. You will need to test to see if the point you get better performance is at 4 rows or 4,000 rows. The only way to know is try both ways and test.)
Let's say i have some items, that have a defined length and horizontal position (both are constant) :
1 : A
2 : B
3 : CC
4 : DDD (item 4 start at position 1, length = 3)
5 : EE
6 : F
I'd like to pack them vertically, resulting in a rectangle having smallest height as possible.
Until now, I have some very simple algorithm that loops over the items and that check row by row if placing them in that row is possible (that means without colliding with something else). Sometimes, it works perfectly (by chance) but sometimes, it results in non-optimal solution.
Here is what it would give for the above example (step by step) :
A | A B | ACC B | ACC B | ACC B | ACC B |
DDD | DDD | FDDD |
EE | EE |
While optimal solution would be :
ADDDB
FCCEE
Note : I have found that sorting items by their length (descending order) first, before applying algorithm, give better results (but it is still not perfect).
Is there any algorithm that would give me optimal solution in reasonable time ? (trying all possibilities is not feasible)
EDIT : here is an example that would not work using sorting trick and that would not work using what TylerOhlsen suggested (unless i dont understand his answer) :
1 : AA
2 : BBB
3 : CCC
4 : DD
Would give :
AA BBB
CCC
DD
Optimal solution :
DDBBB
AACCC
Just spitballing (off the top of my head and just pseudocode ). This algorithm is looping through positions of the current row and attempts to find the best item to place at the position and then moves on to the next row when this row completes. The algorithm completes when all items are used.
The key to the performance of this algorithm is creating an efficient method which finds the longest item at a specific position. This could be done by creating a dictionary (or hash table) of: key=positions, value=sorted list of items at that position (sorted by length descending). Then finding the longest item at a position is as simple as looking up the list of items by position from that hash table and popping the top item off that list.
int cursorRow = 0;
int cursorPosition = 0;
int maxRowLength = 5;
List<Item> items = //fill with item list
Item[][] result = new Item[][];
while (items.Count() > 0)
(
Item item = FindLongestItemAtPosition(cursorPosition);
if (item != null)
{
result[cursorRow][cursorPosition] = item;
items.Remove(item);
cursorPosition += item.Length;
}
else //No items remain with this position
{
cursorPosition++;
}
if (cursorPosition == maxRowLength)
{
cursorPosition = 0;
cursorRow++;
}
}
This should result in the following steps for Example 1 (at the beginning of each loop)...
Row=0 | Row=0 | Row=0 | Row=1 | Row=1 | Row=1 | Row=2 |
Pos=0 | Pos=1 | Pos=4 | Pos=0 | Pos=1 | Pos=3 | Pos=0 |
| A | ADDD | ADDDB | ADDDB | ADDDB | ADDDB |
F | FCC | FCCEE |
This should result in the following steps for Example 2 (at the beginning of each loop)...
Row=0 | Row=0 | Row=0 | Row=1 | Row=1 | Row=1 | Row=2 |
Pos=0 | Pos=2 | Pos=4 | Pos=0 | Pos=1 | Pos=3 | Pos=0 |
| AA | AACCC | AACCC | AACCC | AACCC | AACCC |
DD | DDBBB |
This is a classic Knapsack Problem. As #amit said, it is NP-Complete. The most efficient solution makes use of Dynamic Programming to solve.
The Wikipedia page is a very good start. I've never implemented any algorithm to solve this problem, but I've studied it relation with the minesweeper game, which is also NP-Complete.
Wikipedia: Knapsack Problem