Understanding solution to finding optimal strategy for game involving picking pots of gold - algorithm

I am having trouble understanding the reasoning behind the solution to this question on CareerCup.
Pots of gold game: Two players A & B. There are pots of gold arranged
in a line, each containing some gold coins (the players can see how
many coins are there in each gold pot - perfect information). They get
alternating turns in which the player can pick a pot from one of the
ends of the line. The winner is the player which has a higher number
of coins at the end. The objective is to "maximize" the number of
coins collected by A, assuming B also plays optimally. A starts the
game.
The idea is to find an optimal strategy that makes A win knowing that
B is playing optimally as well. How would you do that?
At the end I was asked to code this strategy!
This was a question from a Google interview.
The proposed solution is:
function max_coin( int *coin, int start, int end ):
if start > end:
return 0
// I DON'T UNDERSTAND THESE NEXT TWO LINES
int a = coin[start] + min(max_coin(coin, start+2, end), max_coin(coin, start+1, end-1))
int b = coin[end] + min(max_coin(coin, start+1,end-1), max_coin(coin, start, end-2))
return max(a,b)
There are two specific sections I don't understand:
In the first line why do we use the ranges [start + 2, end] and [start + 1, end - 1]? It's always leaving out one coin jar. Shouldn't it be [start + 1, end] because we took the starting coin jar out?
In the first line, why do we take the minimum of the two results and not the maximum?
Because I'm confused about why the two lines take the minimum and why we choose those specific ranges, I'm not really sure what a and b actually represent?

First of all a and b represent respectively the maximum gain if start (respectively end) is played.
So let explain this line:
int a = coin[start] + min(max_coin(coin, start+2, end), max_coin(coin, start+1, end-1))
If I play start, I will immediately gain coin[start]. The other player now has to play between start+1 and end. He plays to maximize his gain. However since the number of coin is fixed, this amounts to minimize mine. Note that
if he plays start+1 I'll gain max_coin(coin, start+2, end)
if he plays end Ill gain max_coin(coin, start+1, end-1)
Since he tries to minimize my gain, I'll gain the minimum of those two.
Same reasoning apply to the other line where I play end.
Note: This is a bad recursive implementation. First of all max_coin(coin, start+1, end-1) is computed twice. Even if you fix that, you'll end up computing lots of time shorter case. This is very similar to what happens if you try to compute Fibonacci numbers using recursion. It would be better to use memoization or dynamic programming.

a and b here represent the maximum A can get by picking the starting pot or the ending pot, respectively.
We're actually trying to maximize A-B, but since B = TotalGold - A, we're trying to maximize 2A - TotalGold, and since TotalGold is constant, we're trying to maximize 2A, which is the same as A, so we completely ignore the values of B's picks and just work with A.
The updated parameters in the recursive calls include B picking as well - so coin[start] represents A picking the start, then B picks the next one from the start, so it's start+2. For the next call, B picks from the end, so it's start+1 and end-1. Similarly for the rest.
We're taking the min, because B will try to maximize it's own profit, so it will pick the choice that minimizes A's profit.
But actually I'd say this solution is lacking a bit in the sense that it just returns a single value, not 'an optimal strategy', which, in my mind, would be a sequence of moves. And it also doesn't take into account the possibility that A can't win, in which case one might want to output a message saying that it's not possible, but this would really be something to clarify with the interviewer.

Let me answer your points in reverse order, somehow it seems to make more sense that way.
3 - a and b represent the amount of coins the first player will get, when he/she chooses the first or the last pot respectively
2 - we take the minimum because it is the choice of the second player - he/she will act to minimise the amount of coins the first player will get
1 - the first line presents the scenario - if the first player has taken the first pot, what will the second player do? If he/she again takes the first pot, it will leave (start+2, end). If he/she takes the last pot, it will leave (start+1, end-1)

Assume what you gain on your turn is x and what you get in all consequent turns is y. Both values represent x+y, where a assumes you take next pot (x=coin[start]) from the front and b assumes you take your next pot (x=coin[end]) from the back.
Now how you compute y.
After your choice, the opponent will use the same optimum strategy (thus recursive calls) to maximise his profit, and you will be left with a the smaller profit for the turn. This is why your y=min(best_strategy_front(), best_strategy_end()) -- your value is the smaller of the two choices that are left because the opponent will take the bigger.
The indexing simply indicates the remaining sequences minus one pot on the front and on the back after you made your choice.

A penny from my end too. I have explained steps in detail.
public class Problem08 {
static int dp[][];
public static int optimalGameStrategy(int arr[], int i, int j) {
//If one single element then choose that.
if(i == j) return arr[i];
//If only two elements then choose the max.
if (i + 1 == j ) return Math.max(arr[i], arr[j]);
//If the result is already computed, then return that.
if(dp[i][j] != -1) return dp[i][j];
/**
* If I choose i, then the array length will shrink to i+1 to j.
* The next move is of the opponent. And whatever he choose, I would want the result to be
* minimum. If he choose j, then array will shrink to i+1, j-1. But if also choose i then
* array will shrink to i+2,j. Whatever he choose, I want the result to be min, hence I take
* the minimum of his two choices.
*
* Similarly for a case, when I choose j.
*
* I will eventually take the maximum of both of my case. :)
*/
int iChooseI = arr[i] + Math.min(optimalGameStrategy(arr, i+1, j-1),
optimalGameStrategy(arr, i+2, j));
int iChooseJ = arr[j] + Math.min(optimalGameStrategy(arr, i+1, j-1),
optimalGameStrategy(arr, i, j-2));
int res = Math.max(iChooseI, iChooseJ );
dp[i][j] = res;
return res;
}
public static void main(String[] args) {
int[] arr = new int[]{5,3,7,10};
dp = new int[arr.length][arr.length];
for(int i=0; i < arr.length; i++) {
for(int j=0; j < arr.length; j++) {
dp[i][j] = -1;
}
}
System.out.println( " Nas: " + optimalGameStrategy(arr, 0, arr.length-1));
}
}

Related

Infected Fish can eat another fish having size less that its own. Minimum number of operation required

An evil scientist has developed an injection that induces insatiable hunger in a fish. On giving this injection, a fish of size x can eat another fish of smaller size y (y < x) and become a fish of size x + y retaining this hunger. An aquarium has a number of fishes of various sizes. The scientist introduces an injected fish into this aquarium with an objective that eventually only 1 fish remains. In order to achieve this, the scientist is allowed only two types of moves: either add a normal fish of any size or remove an existing normal fish from the aquarium. Given the sizes of other fishes in the aquarium and the size of injected fish, write a program to determine the minimum number of moves needed by the scientist to achieve his objective.
For example, suppose there are 5 fishes in the aquarium, the injected fish is of size 10 and the other fishes are of sizes 9, 20, 25, and 100. To ensure that only 1 fish remains in the aquarium the scientist needs to remove the fish of size 100 and add a fish of size 3. So the output is 2. The sequence of steps is shown below. The sizes of fishes in the aquarium at each step are shown in curly braces. The highlighted number is the size of the injected fish.
Input format:
{infectedFish} # {a,b,c,d ... } where a,b,c etc are normal fishs
Example:
10#9,20,25,100 ===> 2
3#25,20,100,400,500 ===> 5
50#25,20,9,100 ===>0
I have used following code to solve the problem.
public static int count(int inf, int a[], int i, int op){
//base case
if(i==a.length){
return op;
}
while(i<a.length && inf>a[i]){
inf+=a[i];
i++;
}
if(i==a.length){
return op;
}
int curr = inf+inf-1;
return Math.min(count(curr, a, i, op+1), count(inf, a, i+1, op+1));
}
Calling it using, System.out.println(count(x, a, 0, 0)); x is infected fish and a is given sorted array;
Is this approach correct? If so, seems like its is having comman subproblem, How can we do memoization?
You can increase the efficiency by slightly modifying your algorithm.
If you have more than one fish to eat, it is not optimal to remove the next one, and then try to eat a fish which is bigger.
When you eat a fish, you become bigger, without any cost.
Therefore, the alternatives are:
Eat the next fish after growing up, i.e. after adding new fishes
Get rid of all remaining fishes
Then, the formula can be simplified as follows, other codes remaining unchanged:
return Math.min(count(curr, a, i, op+1), op + a.length -1 - i);
In this case, you don't need memoization: the count function is following one way only, always increasing its internal values.
Note: I assume here that the fishes are sorted, as mentioned in your code.
Complexity, without taking into account sorting: O(n + log(weight_max/weigth_in))
EDIT: there is another way to speed up the process:
If, at a given time, the number of operation op is greater than the current optimum value, then you can stop the recursion.
As others have answered, greedy can work here. After first eating all smaller fish, each choice point is (1) add the largest possible fish smaller than the current hungry fish, or (2) remove all equal or larger fish. Clearly, removing a fish from the middle is unnecessary since if we could consume a larger one, we could consume that one as well.
The state we would like to optimise is num_current_moves + num_removals_needed. But since we only need a single variable to store the best seen such state, we can update it after every choice, iterating up the sorted list, greedily adding fish. Choice (2) isn't an active change; rather, it's just part of calculating the best seen state at each point.
Iterative JavaScript code:
function f(x, A){
A.sort((a, b) => a - b)
let sum = x
let removals_needed = A.length
let moves = 0
let best = removals_needed
let i = 0
while (i < A.length){
if (sum > A[i]){
sum = sum + A[i]
removals_needed = removals_needed - 1
i = i + 1
// It might not be worth
// trying to grow the fish,
// but the growth rate is
// probably fast enough not
// to add significant time
} else {
sum = sum + (sum - 1)
moves = moves + 1
}
best = Math.min(best, moves + removals_needed)
}
return best
}
var inputs = [
[10, [9,20,25,100]], // 2
[3, [25,20,100,400,500]], // 5
[3, [20,21,22,23,24,25]], // 4
[3, [20,21,22]], // 3
[50, [25,20,9,100]] // 0
]
for (let [x, A] of inputs){
console.log(`${x} -> ${A}`)
console.log(f(x, A))
console.log("")
}
Let's summarize:
There are two possible interventions:
Remove biggest fish, and
Add a fish just smaller than the infected fish.
The infected fish can gobble up all smaller fishes, each time growing by the eaten fish's size.
You want the minimum number of interventions to leave only the devourer.
A far simpler algorithm is:
Sort all normal fishes by size.
The trivial solution is removing all fishes manually.
You have not yet added any new fishes.
Gobble up the smallest fishes as long as possible.
New candidate solution is fishes added plus fishes remaining. Choose the better one.
If no fishes left, you are done.
Grow the devourer to 2*size-1 by adding a fish of size size-1 as often as needed to devour the smallest fish.
Contine with step 4, devouring fishes.
I will make 2 changes to this solution :
1.) Since I didn't see in the question that the Killer fish cannot be of size = 0.
Or of size 1.
I will add that condition to avoid possible infinite loop.
2.)
You are calculating cost on the number of recursions = for increasing the size of fish (SI) + for removing the fish (RF).
I don't see how SI is related to N or
E.g.
N = 100,000 = 10^6
A = [ 10^7, 10^5 + 10^7, 10^6 + 10^8, ........ ] // For actually large size example
If the Infected fish was of size 2.
And the next possible fish it can eat is say 10,000,000.
And total number of fishes are as 10^6.
Now the SI would be recurs-ing over 2, 3, 5, 8..... K etc.
K > 10,000,000
Just to see what is cost/count to make it actually greater than the next possible candidate fish that can be eaten.
So I would not use recursion to calculate that.
I would use simply this logic
cost or count = Ceiling { Ln[(F-1)/(K-1)] } // O(1)
// F = Weight of fish greater than infected fish - at the moment of recursion.
// K - Infected Fish's current weight.
// Ln - Log to the base 2.
// Ceiling will give us the Rounded off value e.g. ceiling (3.4) = 4, ceiling (3.7) = 4.
Now the running cost is simply O(n), if not including the cost for sorting.
public static int HungryFish(int infectedFishSize, int[] fishs)
{
Array.Sort(fishs);
int moves = 0;
for (int i = 0; i < fishs.Length; i++)
{
if (fishs[i] < infectedFishSize)
{
infectedFishSize += fishs[i];
}
else
{
if (fishs[i] < (infectedFishSize + infectedFishSize - 1))
{
infectedFishSize += (infectedFishSize - 1);
moves++;
}
else
{
moves += (fishs.Length - i);
break;
}
}
}
return moves;
}

2048 game: how many moves did I do?

2048 used to be quite popular just a little while ago. Everybody played it and a lot of people posted nice screenshots with their accomplishments(myself among them). Then at some point I began to wonder if it possible to tell how long did someone play to get to that score. I benchmarked and it turns out that(at least on the android application I have) no more than one move can be made in one second. Thus if you play long enough(and fast enough) the number of moves you've made is quite good approximation to the number of seconds you've played. Now the question is: is it possible having a screenshot of 2048 game to compute how many moves were made.
Here is an example screenshot(actually my best effort on the game so far):
From the screenshot you can see the field layout at the current moment and the number of points that the player has earned. So: is this information enough to compute how many moves I've made and if so, what is the algorithm to do that?
NOTE: I would like to remind you that points are only scored when two tiles "combine" and the number of points scored is the value of the new tile(i.e. the sum of the values of the tiles being combined).
The short answer is it is possible to compute the number of moves using only this information. I will explain the algorithm to do that and I will try to post my answer in steps. Each step will be an observation targeted at helping you solve the problem. I encourage the reader to try and solve the problem alone after each tip.
Observation number one: after each move exactly one tile appears. This tile is either 4 or 2. Thus what we need to do is to count the number of tiles that appeared. At least on the version of the game I played the game always started with 2 tiles with 2 on them placed at random.
We don't care about the actual layout of the field. We only care about the numbers that are present on it. This will become more obvious when I explain my algorithm.
Seeing the values in the cells on the field we can compute what the score would be if 2 had appeared after each move. Call that value twos_score.
The number of fours that have appeared is equal to the difference of twos_score and actual_score divided by 4. This is true because for forming a 4 from two 2-s we would have scored 4 points, while if the 4 appears straight away we score 0. Call the number of fours fours.
We can compute the number of twos we needed to form all the numbers on the field. After that we need to subtract 2 * fours from this value as a single 4 replaces the need of two 2s. Call this twos.
Using this observations we are able to solve the problem. Now I will explain in more details how to perform the separate steps.
How to compute the score if only two appeared?
I will prove that to form the number 2n, the player would score 2n*(n - 1) points(using induction).
The statements is obvious for 2 as it directly appears and therefor no points are scored for it.
Let's assume that for a fixed k for the number 2k the user will score 2k*(k - 1)
For k + 1: 2k + 1 can only be formed by combining two numbers of value 2k. Thus the user will score 2k*(k - 1) + 2k*(k - 1) + 2k+1(the score for the two numbers being combined plus the score for the new number).
This equals: 2k + 1*(k - 1) + 2k+1= 2k+1 * (k - 1 + 1) = 2k+1 * k. This completes the induction.
Therefor to compute the score if only twos appeared we need to iterate over all numbers on the board and accumulate the score we get for them using the formula above.
How to compute the number of twos needed to form the numbers on the field?
It is much easier to notice that the number of twos needed to form 2n is 2n - 1. A strict proof can again be done using induction, but I will leave this to the reader.
The code
I will provide code for solving the problem in c++. However I do not use anything too language specific(appart from vector which is simply a dynamically expanding array) so it should be very easy to port to many other languages.
/**
* #param a - a vector containing the values currently in the field.
* A value of zero means "empty cell".
* #param score - the score the player currently has.
* #return a pair where the first number is the number of twos that appeared
* and the second number is the number of fours that appeared.
*/
pair<int,int> solve(const vector<vector<int> >& a, int score) {
vector<int> counts(20, 0);
for (int i = 0; i < (int)a.size(); ++i) {
for (int j = 0; j < (int)a[0].size(); ++j) {
if (a[i][j] == 0) {
continue;
}
int num;
for (int l = 1; l < 20; ++l) {
if (a[i][j] == 1 << l) {
num = l;
break;
}
}
counts[num]++;
}
}
// What the score would be if only twos appeared every time
int twos_score = 0;
for (int i = 1; i < 20; ++i) {
twos_score += counts[i] * (1 << i) * (i - 1);
}
// For each 4 that appears instead of a two the overall score decreases by 4
int fours = (twos_score - score) / 4;
// How many twos are needed for all the numbers on the field(ignoring score)
int twos = 0;
for (int i = 1; i < 20; ++i) {
twos += counts[i] * (1 << (i - 1));
}
// Each four replaces two 2-s
twos -= fours * 2;
return make_pair(twos, fours);
}
Now to answer how many moves we've made we should add the two values of the pair returned by this function and subtract two because two tiles with 2 appear straight away.

Divvying people into rooms by last name?

I often teach large introductory programming classes (400 - 600 students) and when exam time comes around, we often have to split the class up into different rooms in order to make sure everyone has a seat for the exam.
To keep things logistically simple, I usually break the class apart by last name. For example, I might send students with last names A - H to one room, last name I - L to a second room, M - S to a third room, and T - Z to a fourth room.
The challenge in doing this is that the rooms often have wildly different capacities and it can be hard to find a way to segment the class in a way that causes everyone to fit. For example, suppose that the distribution of last names is (for simplicity) the following:
Last name starts with A: 25
Last name starts with B: 150
Last name starts with C: 200
Last name starts with D: 50
Suppose that I have rooms with capacities 350, 50, and 50. A greedy algorithm for finding a room assignment might be to sort the rooms into descending order of capacity, then try to fill in the rooms in that order. This, unfortunately, doesn't always work. For example, in this case, the right option is to put last name A in one room of size 50, last names B - C into the room of size 350, and last name D into another room of size 50. The greedy algorithm would put last names A and B into the 350-person room, then fail to find seats for everyone else.
It's easy to solve this problem by just trying all possible permutations of the room orderings and then running the greedy algorithm on each ordering. This will either find an assignment that works or report that none exists. However, I'm wondering if there is a more efficient way to do this, given that the number of rooms might be between 10 and 20 and checking all permutations might not be feasible.
To summarize, the formal problem statement is the following:
You are given a frequency histogram of the last names of the students in a class, along with a list of rooms and their capacities. Your goal is to divvy up the students by the first letter of their last name so that each room is assigned a contiguous block of letters and does not exceed its capacity.
Is there an efficient algorithm for this, or at least one that is efficient for reasonable room sizes?
EDIT: Many people have asked about the contiguous condition. The rules are
Each room should be assigned at most a block of contiguous letters, and
No letter should be assigned to two or more rooms.
For example, you could not put A - E, H - N, and P - Z into the same room. You could also not put A - C in one room and B - D in another.
Thanks!
It can be solved using some sort of DP solution on [m, 2^n] space, where m is number of letters (26 for english) and n is number of rooms. With m == 26 and n == 20 it will take about 100 MB of space and ~1 sec of time.
Below is solution I have just implemented in C# (it will successfully compile on C++ and Java too, just several minor changes will be needed):
int[] GetAssignments(int[] studentsPerLetter, int[] rooms)
{
int numberOfRooms = rooms.Length;
int numberOfLetters = studentsPerLetter.Length;
int roomSets = 1 << numberOfRooms; // 2 ^ (number of rooms)
int[,] map = new int[numberOfLetters + 1, roomSets];
for (int i = 0; i <= numberOfLetters; i++)
for (int j = 0; j < roomSets; j++)
map[i, j] = -2;
map[0, 0] = -1; // starting condition
for (int i = 0; i < numberOfLetters; i++)
for (int j = 0; j < roomSets; j++)
if (map[i, j] > -2)
{
for (int k = 0; k < numberOfRooms; k++)
if ((j & (1 << k)) == 0)
{
// this room is empty yet.
int roomCapacity = rooms[k];
int t = i;
for (; t < numberOfLetters && roomCapacity >= studentsPerLetter[t]; t++)
roomCapacity -= studentsPerLetter[t];
// marking next state as good, also specifying index of just occupied room
// - it will help to construct solution backwards.
map[t, j | (1 << k)] = k;
}
}
// Constructing solution.
int[] res = new int[numberOfLetters];
int lastIndex = numberOfLetters - 1;
for (int j = 0; j < roomSets; j++)
{
int roomMask = j;
while (map[lastIndex + 1, roomMask] > -1)
{
int lastRoom = map[lastIndex + 1, roomMask];
int roomCapacity = rooms[lastRoom];
for (; lastIndex >= 0 && roomCapacity >= studentsPerLetter[lastIndex]; lastIndex--)
{
res[lastIndex] = lastRoom;
roomCapacity -= studentsPerLetter[lastIndex];
}
roomMask ^= 1 << lastRoom; // Remove last room from set.
j = roomSets; // Over outer loop.
}
}
return lastIndex > -1 ? null : res;
}
Example from OP question:
int[] studentsPerLetter = { 25, 150, 200, 50 };
int[] rooms = { 350, 50, 50 };
int[] ans = GetAssignments(studentsPerLetter, rooms);
Answer will be:
2
0
0
1
Which indicates index of room for each of the student's last name letter. If assignment is not possible my solution will return null.
[Edit]
After thousands of auto generated tests my friend has found a bug in code which constructs solution backwards. It does not influence main algo, so fixing this bug will be an exercise to the reader.
The test case that reveals the bug is students = [13,75,21,49,3,12,27,7] and rooms = [6,82,89,6,56]. My solution return no answers, but actually there is an answer. Please note that first part of solution works properly, but answer construction part fails.
This problem is NP-Complete and thus there is no known polynomial time (aka efficient) solution for this (as long as people cannot prove P = NP). You can reduce an instance of knapsack or bin-packing problem to your problem to prove it is NP-complete.
To solve this you can use 0-1 knapsack problem. Here is how:
First pick the biggest classroom size and try to allocate as many group of students you can (using 0-1 knapsack), i.e equal to the size of the room. You are guaranteed not to split a group of student, as this is 0-1 knapsack. Once done, take the next biggest classroom and continue.
(You use any known heuristic to solve 0-1 knapsack problem.)
Here is the reduction --
You need to reduce a general instance of 0-1 knapsack to a specific instance of your problem.
So lets take a general instance of 0-1 knapsack. Lets take a sack whose weight is W and you have x_1, x_2, ... x_n groups and their corresponding weights are w_1, w_2, ... w_n.
Now the reduction --- this general instance is reduced to your problem as follows:
you have one classroom with seating capacity W. Each x_i (i \in (1,n)) is a group of students whose last alphabet begins with i and their number (aka size of group) is w_i.
Now you can prove if there is a solution of 0-1 knapsack problem, your problem has a solution...and the converse....also if there is no solution for 0-1 knapsack, then your problem have no solution, and vice versa.
Please remember the important thing of reduction -- general instance of a known NP-C problem to a specific instance of your problem.
Hope this helps :)
Here is an approach that should work reasonably well, given common assumptions about the distribution of last names by initial. Fill the rooms from smallest capacity to largest as compactly as possible within the constraints, with no backtracking.
It seems reasonable (to me at least) for the largest room to be listed last, as being for "everyone else" not already listed.
Is there any reason to make life so complicated? Why cann't you assign registration numbers to each student and then use the number to allocate them whatever the way you want :) You do not need to write a code, students are happy, everyone is happy.

Determine if more than half of the array repeats in a distinct array

I was looking at the following question from Glassdoor:
Given N credits cards, determine if more than half of them belong to the same person/owner. All you have is an array of the credit card numbers, and an api call like isSamePerson(num1, num2).
It is clear how to do it in O(n^2) but some commenters said it can be done in O(n) time. Is it even possible? I mean, if we have an array of credit card numbers where some numbers are repeated, then the claim makes sense. However, we need to make an API call for each credit card number to see its owner.
What am I missing here?
The algorithm goes as follows:
If there is a majority of one item (here, a person), then if you pair together items that are not equal (in any order), this item will be left over.
Start with an empty candidate slot
For every item
If the candidate slot is empty (count = 0), place it there.
Else if it is equal to the item in the slot, increment its count.
Else decrement the count for that slot(pop one item).
If there is nothing left on the candidate slot, there is no clear majority. Otherwise,
Count the number of occurences of the candidate (second pass).
If the number of occurences is more than 50%, declare it a winner,
Else there is no majority.
Note this cannot be applied if the threshold is below 50% (but it should be possible to adapt to a threshold of 33%, 25%... by holding two, three... candidate slots and popping only a distinct triple, quadruple...).
This also apllies to the case of the credit cards: All you need to is compare two elements (persons) for equality (via the API call), and a counter that is able to accomodate the total number of elements.
Time complexity: O(N)
Space complexity: O(1) + input
API calls: up to 2N-1: once in each pass, no api call for the first element in the first pass.
Let x1,x2,...,xn be the credit card numbers.
Note that since more than half of them belong to same person, if you consider two adjacent numbers, at least one pair of them are going to belong to same person.
If you consider all pairs (x1,x2), (x3,x4)...., and consider the subset of pairs where both elements belong to same person, a majority of same-person-pairs belong to the person who has majority of cards in first place. So, for every same-person-pair keep one of the card numbers and for non-same-person-pairs discard both. Do this recursively and return the last remaining same-person-pair.
You need to perform at most n comparisons.
NOTE: If n is odd keep the unpaired number.
Why this works: consider a case where n is even and person A owns n/2 + 1 cards. In the worst case you have exactly one pair where both cards are owned by A. In that case none of the other pairs are owned by same person ( other pairs contain one card of A and a card by other person).
Now, to create one matching pair of B (non-A person), you have to create one pair of B also. Therefore, at every instance a majority of matching pairs are owned by A.
I don't have reputation to comment. The method told by Jan Dvorak is known as Moore's Voting Algorithm (Stream Counting Algorithm). Here's the code.
int majorityElement(int* nums, int numsSize) {
int count =0, i, majorityElement;
/*Moore's voting algorithm Order(n), Auxiliary space: Order(1)*/
/*step:1-To get candidate for the majority element*/
for(i=0; i < numsSize; i++)
{
if(count==0)
majorityElement = nums[i];
if(nums[i]==majorityElement)
count++;
else
count--;
}
/*Step:2- To check whether this candidate occurs max no. of times */
count =0;
for(i=0; i<numsSize; i++)
{
if(nums[i]==majorityElement)
count ++;
}
if(count>numsSize/2) /*It can only be applied for majority check */
return majorityElement;
return -1;}
The question is to find out the majority element in an array. I shall use
Boyer-Moore Majority Vote algorithm. I am doing this using HashMap.
public class majorityElement1 {
public static void main(String[] args) {
int a[] = {2,2,2,2,5,5,2,3,3,3,3,3,3,33,3};
fix(a);
}
public static void fix(int[] a ) {
Map<Integer,Integer> map = new HashMap<>();
for(int i = 0 ; i<a.length ; i++) {
int r = a[i];
if(!map.containsKey(r)) {
map.put(r, 1);
}else {
if(map.get(r) +1 >= a.length/2) {
System.out.println("majority element => "+ r);
return ;
}else {
map.put(r,map.get(r) +1);
}
}//else1
}//for
}
}
The output is 3.
DONE IN ONE PASS :
Start from the the second index of array let say i=1 initially.
Initially count=1.
Call isSamePerson(a[i],a[i-1]) where array a[] contains credit card numbers.
If the returned value is positive , do count++ and i++
else if returned value is 0 and count==1 , i++
else if returned value is 0 and count>1 , do count-- and i++
If i!=(n-1) , go to step 3 where n is number of cards.
else If at the end of array count>1 , then there are more than half of cards belonging to a single person
else there is no clear majority of over 50%.
I hope that this is understandable and writing code would be an easy thing.
TIME COMPLEXITY - O(N)
NUMBER OF API CALLS = N-1
SPACE COMPLEXITY - O(1)

Algorithm to find out all the possible positions

I need an algorithm to find out all the possible positions of a group of pieces in a chessboard. Like finding all the possible combinations of the positions of a number N of pieces.
For example in a chessboard numbered like cartesian coordinate systems any piece would be in a position
(x,y) where 1 <= x <= 8 and 1 <= y <= 8
I'd like to get an algorithm which can calculate for example for 3 pieces all the possible positions of the pieces in the board. But I don't know how can I get them in any order. I can get all the possible positions of a single piece but I don't know how to mix them with more pieces.
for(int i = 0; i<= 8; i++){
for(int j = 0; j<= 8; j++){
System.out.println("Position: x:"+i+", y:"+j);
}
}
How can I get a good algoritm to find all the posible positions of the pieces in a chessboard?
Thanks.
You got 8x8 board, so total of 64 squares.
Populate a list containing these 64 sqaures [let it be list], and find all of the possibilities recursively: Each step will "guess" one point, and invoke the recursve call to find the other points.
Pseudo code:
choose(list,numPieces,sol):
if (sol.length == numPieces): //base clause: print the possible solution
print sol
return
for each point in list:
sol.append(point) //append the point to the end of sol
list.remove(point)
choose(list,numPieces,sol) //recursive call
list.add(point) //clean up environment before next recursive call
sol.removeLast()
invoke with choose(list,numPieces,[]) where list is the pre-populated list with 64 elements, and numPieces is the pieces you are going to place.
Note: This solution assumes pieces are not identical, so [(1,2),(2,1)] and [(2,1),(1,2)] are both good different solutions.
EDIT:
Just a word about complexity, since there are (n^2)!/(n^2-k)! possible solutions for your problem - and you are looking for all of them, any algorithm will suffer from exponential run time, so trying to invoke it with just 10 pieces, will take ~400 years
[In the above notation, n is the width and length of the board, and k is the number of pieces]
You can use a recursive algorithm to generate all possiblities:
void combine(String instr, StringBuffer outstr, int index)
{
for (int i = index; i < instr.length(); i++)
{
outstr.append(instr.charAt(i));
System.out.println(outstr);
combine(instr, outstr, i + 1);
outstr.deleteCharAt(outstr.length() - 1);
}
}
combine("abc", new StringBuffer(), 0);
As I understand you should consider that some firgure may come block some potential position for figures that can reach them on the empty board. I guess it is the most tricky part.
So you should build some set of vertexes (set of board states) that is reached from some single vertex (initial board state).
The first algorithm that comes to my mind:
Pre-conditions:
Order figures in some way to form circle.
Assume initial set of board states (S0) to contain single element which represents inital board state.
Actions
Choose next figure to extend set of possible positions
For each state of board within S(n) walk depth-first all possible movements that new board states and call it F(n) (frame).
Form S(n+1) = S(n) ∪ F(n).
Repeat steps till all frames of updates during whole circle pass will not be empty.
This is kind of mix breath-first and depth-first search

Resources