Related
Assume there are n prisoners standing in a circle. The first prisoner has a knife with which he kills the second prisoner and passes on the knife to the third person who kills the fourth prisoner and passes the knife to the fifth prisoner.
This cycle is repeated till only one prisoner is left. Note that the prisoners are standing in a circle, thus the first prisoner is next to the nth prisoner. Return the index of the last standing prisoner.
I tried implementing the solution using a circular linked list. Here's my code
The structure of the circular linked list is:-
struct Node
{
int Data;
Node *Next;
};
Node *Head = NULL;
Here are my deleteByAddress() and main() functions:-
inline void deleteByAddress(Node *delNode)
{
Node *n = Head;
if(Head == delNode)
{
while(n -> Next != Head)
{
n = n -> Next;
}
n -> Next = Head -> Next;
free(Head);
Head = n -> Next;
return ;
}
while(n -> Next != delNode)
{
n = n -> Next;
}
n -> Next = delNode -> Next;
delete delNode;
}
int main(void)
{
for(int i = 1 ; i <= 100 ; i++)
insertAtEnd(i);
Node *n = Head;
while(Head -> Next != Head)
{
deleteByAddress(n -> Next);
n = n -> Next;
}
cout << Head -> Data;
return 0;
}
The above code works perfectly and produces the desired output for n = 100, which is 73.
Is there any way we can reduce the time complexity or use a more efficient data structure to implement the same question.
This is known as the Josephus problem. As the Wikipedia page shows and others have noted, there is a formula for when k is 2. The general recurrence is
// zero-based Josephus
function g(n, k){
if (n == 1)
return 0
return (g(n - 1, k) + k) % n
}
console.log(g(100, 2) + 1)
This can easily be solved with O(1) complexity using the following:
last = (num - pow(2, int(log(num)/log(2)))) * 2 + 1
for example for num = 100 :
last = (100 - pow(2, int(log(100)/log(2)))) * 2 + 1 = 73
And if you have log2() function, you may replace a bit ugly log(num)/log(2) which basically takes a logarithm with the base 2.
Use 1 loop. You can grab, at every iteration, the current one's next, then set current to the next ones next and then delete the next one.
This assumes all the data is set up before hand and ignores the rewriting of the next variable when you hit the bounds.
The trick to reduce time complexity is to come up with more clever algorithms than brute-forcing it by simulation.
Here, as so often, key is obviously to solve the math. The first loop, for example, kills everybody with i%2=1 (assuming 0 based indexing), the second everybody with i%4=(n+1)%2*2 or so etc. - I'd be looking for a closed form to directly compute the survivor. It will likely boil down to a few bit manipulations yielding a O(log n) algorithm that is almost instant in practise because of all running completely in CPU registers with not even L1 cache accesses.
For such a simple processing the list manipulation and memory allocation is going to dominate the computation, you could use just a single array where you have an index to the first alive and each element is the index of next alive.
That said you could indeed search for a formula that avoids doing the loops... for example if the number of prisoners is even then after the first "loop" you end up with half of the prisoners and the knife back in the hands of first one. This means that the index of the surviving prisoner when n is even is
f(n) = 2 * f(n / 2) # when n is even
in case n is odd things are a bit more complex... after the first loop you will end up with (n + 1)/2 prisoners, but the knife in the hand of last one so some modulo arithmetic is needed because you need to "adjust" the result of the recursive call f((n + 1)/2).
The method to reduce time complextiy is, as in most cases that a challenge fails for out-of-time reasons, to not simulate and use math instead. With luck it turns into a one-liner.
The algorithm can be sped up very much, if you change to:
Note that for a total number of prisoners which is a power of two, always index 0 will survive.
For other cases:
determine the highest power of two which is lower or equal to the number of prisoners
determine R, the rest when reducing the number of prisoners by that power of two
the prisoner who survives in the end will be the one who gets the knife after that number of prisoners has been killed
Trying to find out which prisoner that is.
Case of 5 prisoners (1 higher than 22, R=1):
01234
Deaths 1: x x
Deaths 2:x x
last : O
Case of 6 (R=2):
012345
Deaths 1: x x x
Deaths 2:x x (index 4 kills index 0 after index 2 was killed by index 0)
last : O
Case of 7 (R=3):
0123456
Deaths 1:xx x x (index 6 kills index 0 after index 5 was killed by index 2)
Deaths 2: x x (index 6 kills index 2 after index 4 was killed by index 2)
last : O
Case of 8 is the next power of two, index 0 survives.
In the end, the final survivor is always the one at index 2*R.
Hence, instead of simulating, you just need to determine R.
That should be possible at worst in a time complexity of order of logarithm to base 2 of total number.
void insert(int number){
Node* temp0 = NULL;
Node* temp1 = head;
Node* temp = new Node();
int sum = 0;
while(temp1!= NULL && sum<=number){
// loop condition edited, before it was temp1!= NULL && sum>=number
sum+=temp1->content;
temp0=temp1;
temp1=temp1->next;
}
if(temp0 == NULL){
temp->content = number;
temp->next = head;
if(head!=NULL){
head->content -= temp->content;
}
head = temp;
}
else{
temp0->next = temp;
temp->content = number - sum;
temp1->content -= temp->content;
temp->next = temp1;
}// end of else
}// end of void insert
I ran into a problem, which i described in one of my previous questions, but still, i'm looking to implement the solution on my own.
In short, i want to make a "relative" list:
for example, for elements 1 5 7 2 4 6 the list would look like 1 1 2 1 1 1
I would make a priority queue list 1 2 4 5 7 6, and then i would change elements relative to the previous one:first element would stay 1,second would be 2-1 = 1, third would be 4-2 = 2, fourth 5-4 = 1 and so on.
When i form a priority queue, i would replace the current element with the difference of it's value and the value of the previous element.
I'm having problems implementing the insert feature. The code is given at the top of the question.
The idea is, i go through the list, adding the "difference" (which is the content field of my Node* structure) to a counter variable. When the sum counter becomes greater or equal to the element i need to insert, i found the position where to insert it.
If temp0 is null, i insert the element on the first position. If it's not the only element, i update the content of the next element - head, which was the previous first element.
If the number needs to be inserted somewhere in the middle of the list (or at the end), i update the content as sum - number, which would be a number >= 0, which is okay. Also, i update the content of the new's next element (temp1) as temp->content - temp->content.
For some reason, this does not work.
When i insert 4 2 8, instead of 2 2 4, i'm getting 4 -2 6 as the result list.
Your loop is "wrong", sum starts out being 0, so as long as number is not zero or negative, it never enters "find the place" loop. So every number is inserted at the beginning, rather than in its rightful place.
while(temp1!= NULL && sum>=number){
sum+=temp1->content;
temp0=temp1;
temp1=temp1->next;
}
Change it to sum <= number, and I believe it will work. Not sure what you want to have happen if you insert the same number multiple times... May you want sum < number instead?
Edit: You will also have some method to detect that your "new" value is less than the existing one, and if so insert a new head, rather than after the existing number. I'm not sure what the exact code for this would be, but you do need to do something along the lines of:
if (number < sum)
{
temp->next = head;
head->content -= temp->content;
head = temp;
}
else
{
... existing insert code ...
}
Question : A company hiring candidates, makes them sit in a circle.
They select every second candidate and he leaves the circle (thus circle keeps getting smaller), till only 1 is left.
So, if there are 5 people, it'll be like :-
1 2 3 4 5
1 3 4 5 (2 is selected)
1 3 5 (4 is selected)
3 5 (1 is selected)
3 (3 is left, does'nt get the job!)
Jhon an oversmart guy doesn't want to be a part of this spiteful company.
Where does he stand if he knows that there are 560 people in total.
Ans : I tried to make a program where you enter n(number of candidates)
and it'll print the value of the one seat that will go unselected.
I Used circular linked list and deletion.
Please bear with me , as i am fairly new to coding .
My program works for inputs 2, 4, 8, 16, 32, 64 and so on as ans in all these is 1.
But any other input and it's not working.
#include <iostream>
using namespace std;
struct node
{
node* ptr;
int data;
}start;
int main()
{
node *start=NULL;
int n;
cout<<"Enter the number of students : ";
cin>>n;
node *temp=new node;
temp->data=1;
temp->ptr=NULL;
start=temp;
for(int x=2;x<=n;x++)
{
node* temp1=new node;
temp1->data=x;
temp->ptr=temp1;
temp1->ptr=start;
temp=temp1;
}
node* temp2=start;
do
{
cout<<temp2->data<<" ";
temp2=temp2->ptr;
}while(temp2!=start);
cout<<endl;
//delete bigins here
temp2=start;
node* temp3=temp2->ptr;
do
{
temp2->ptr=temp3->ptr;
temp3->ptr=NULL;
delete temp3;
temp2=temp2->ptr;
temp3=temp2->ptr;
}while(temp2->ptr!=start);
temp2=start;
do
{
cout<<temp2->data<<" ";
temp2=temp2->ptr;
}while(temp2!=temp3);
cout<<endl;
}
My program works for inputs 2, 4, 8, 16, 32, 64 and so on as ans in all these is 1.
This is a good observation. Actually the answer is just a small step from here.
You have n candidates, and you select 1 each time. If n is x + 2^k (with the biggest possible k), after x steps you have 2^k candidates left and the next candidate in the line is the answer. So the answer is 2x+1.
1 2 3 4 5 6 7
^ ^ ^ |
removed |
answer
Note: This exercise can be found in Concrete Mathematics: Foundation for Computer Science. I highly recommend it.
The issue lies in the core loop:
do {
temp2->ptr=temp3->ptr;
temp3->ptr=NULL;
delete temp3;
temp2=temp2->ptr;
temp3=temp2->ptr;
} while (temp2->ptr!=start);
This loop goes through the data once only: it stops when it gets to the end of the first set of removals, because it stops the first time it gets back to start. That's why you always get the answer 1, which, as you point out, is correct when the list length is a power of 2.
Rather, it should loop until there is only one node left, which will point to itself as the next node. So the last line of the do ... while loop should be:
} while (temp2->ptr != temp2)
Clearly the world has moved on: the first time I heard this puzzle it was about pirates drinking poison to determine who got the treasure!
to greatly simplify your solution, implement a "soft delete". Put a flag on your node struct called "int deleted" and initialize it to 0. Each time you want to delete a node, just set deleted = 1. Your pointer logic in your question is having problems and this gets rid of most of it.
When you're looking for the next one to delete, if the node has deleted == 1, then don't count it as one of the remaining ones, just keep going until you find the second node with deleted = 0, and set it to 1.
You don't even really need a circular list, or even a list at this point. You can just use an array of ints with values of 0 or 1. If you keep a count of how many are still around, then you can stop as soon as you get to just one remaining, otherwise you would have to traverse the whole array to make sure there are none left.
This isn't as fast, as your list never gets smaller and you're looking at a lot of deleted entries, but it's a ton simpler.
There is a small error in the second do while loop (deletion). The while statement forces the termination of loop after iterating through it once, i.e., once it reaches back the the start node, it exits. You need to change the line
while(temp2->ptr!=start);
to
while(temp2->ptr!=temp2);
Also the last do while loop seems to run into an infinite loop because of the statement just above it:
temp2 = start;
During deletion, you do not keep track of the start pointer which gets removed as soon as element 1 is deleted. Thus temp2 points to garbage then. Removing this line should fix that too.
I've just started learning Backtracking algorithms at college. Somehow I've managed to make a program for the Subset-Sum problem. Works fine but then i discovered that my program doesn't give out all the possible combinations.
For example : There might be a hundred combinations to a target sum but my program gives only 30.
Here is the code. It would be a great help if anyone could point out what my mistake is.
int tot=0;//tot is the total sum of all the numbers in the set.
int prob[500], d, s[100], top = -1, n; // n = number of elements in the set. prob[i] is the array with the set.
void subset()
{
int i=0,sum=0; //sum - being updated at every iteration and check if it matches 'd'
while(i<n)
{
if((sum+prob[i] <= d)&&(prob[i] <= d))
{
s[++top] = i;
sum+=prob[i];
}
if(sum == d) // d is the target sum
{
show(); // this function just displays the integer array 's'
top = -1; // top points to the recent number added to the int array 's'
i = s[top+1];
sum = 0;
}
i++;
while(i == n && top!=-1)
{
sum-=prob[s[top]];
i = s[top--]+1;
}
}
}
int main()
{
cout<<"Enter number of elements : ";cin>>n;
cout<<"Enter required sum : ";cin>>d;
cout<<"Enter SET :\n";
for(int i=0;i<n;i++)
{
cin>>prob[i];
tot+=prob[i];
}
if(d <= tot)
{
subset();
}
return 0;
}
When I run the program :
Enter number of elements : 7
Enter the required sum : 12
Enter SET :
4 3 2 6 8 12 21
SOLUTION 1 : 4, 2, 6
SOLUTION 2 : 12
Although 4, 8 is also a solution, my program doesnt show it.
Its even worse with the number of inputs as 100 or more. There will be atleast 10000 combinations, but my program shows 100.
The Logic which I am trying to follow :
Take in the elements of the main SET into a subset as long as the
sum of the subset remains less than or equal to the target sum.
If the addition of a particular number to the subset sum makes it
larger than the target, it doesnt take it.
Once it reaches the end
of the set, and answer has not been found, it removes the most
recently taken number from the set and starts looking at the numbers
in the position after the position of the recent number removed.
(since what i store in the array 's' is the positions of the
selected numbers from the main SET).
The solutions you are going to find depend on the order of the entries in the set due to your "as long as" clause in step 1.
If you take entries as long as they don't get you over the target, once you've taken e.g. '4' and '2', '8' will take you over the target, so as long as '2' is in your set before '8', you'll never get a subset with '4' and '8'.
You should either add a possibility to skip adding an entry (or add it to one subset but not to another) or change the order of your set and re-examine it.
It may be that a stack-free solution is possible, but the usual (and generally easiest!) way to implement backtracking algorithms is through recursion, e.g.:
int i = 0, n; // i needs to be visible to show()
int s[100];
// Considering only the subset of prob[] values whose indexes are >= start,
// print all subsets that sum to total.
void new_subsets(int start, int total) {
if (total == 0) show(); // total == 0 means we already have a solution
// Look for the next number that could fit
while (start < n && prob[start] > total) {
++start;
}
if (start < n) {
// We found a number, prob[start], that can be added without overflow.
// Try including it by solving the subproblem that results.
s[i++] = start;
new_subsets(start + 1, total - prob[start]);
i--;
// Now try excluding it by solving the subproblem that results.
new_subsets(start + 1, total);
}
}
You would then call this from main() with new_subsets(0, d);. Recursion can be tricky to understand at first, but it's important to get your head around it -- try easier problems (e.g. generating Fibonacci numbers recursively) if the above doesn't make any sense.
Working instead with the solution you have given, one problem I can see is that as soon as you find a solution, you wipe it out and start looking for a new solution from the number to the right of the first number that was included in this solution (top = -1; i = s[top+1]; implies i = s[0], and there is a subsequent i++;). This will miss solutions that begin with the same first number. You should just do if (sum == d) { show(); } instead, to make sure you get them all.
I initially found your inner while loop pretty confusing, but I think it's actually doing the right thing: once i hits the end of the array, it will delete the last number added to the partial solution, and if this number was the last number in the array, it will loop again to delete the second-to-last number from the partial solution. It can never loop more than twice because numbers included in a partial solution are all at distinct positions.
I haven't analysed the algorithm in detail, but what struck me is that your algorithm doesn't account for the possibility that, after having one solution that starts with number X, there could be multiple solutions starting with that number.
A first improvement would be to avoid resetting your stack s and the running sum after you printed the solution.
During an interview yesterday, I was asked how I would go about summing the values of two singly linked lists that contained digits. They also said the lists could be unequal lengths.
I asked if the list was stored backwards, as that's how I learned about it at uni, but they said no, it was stored forward. They also said I couldn't simply reverse the lists, add then, then reverse it to get it forward again because that option required too much processing. This sort of solution is all I've been able to find online.
I was unable to give an answer, even after they hinted that I should be doing this with a recursive function.
Can anyone help me out with what the solution would have been. This was for a C++ job and I'm hoping that if I ever get called back and I'm able to explain I researched the solution, they might see that as a good sign. Thank you.
For those confused about how the summation is supposed to work, it was presented in this way.
List 1: 1->2->9
List 2: 1->3
So since the numbers are stored forward, I would need to begin by adding the 9 and 3 (end of both lists). Then take the 1 carry and do 1 + 2 + 1. Etc.
You count the length of both lists. You pad at the beginning the shorter list with a number of 0 digits so that they are equal in length. Now you pad both numbers with an extra 0 (it will be used by the carry of the first digits. So that it's possible that 9 + 1 = 10).
You create a third linked list of length equal to the previous two.
Now you do a class like this:
class Digit
{
public:
Digit *Next;
int Dt;
}
and a function like this:
int Sum(const Digit* left, const Digit* right, Digit* runningTotal)
{
int carry = 0;
if (left->Next != NULL)
{
carry = Sum(left->Next, right->Next, runningTotal->Next);
}
carry += left->Dt + right->Dt;
runningTotal->Dt = carry % 10;
carry /= 10;
return carry;
}
This is "version 0".
In "version 1" you remove the extra padding for the last carry and you add it only if needed.
In "version 2" you remove unnecessary "0" digits from the front of the linked lists.
In "version 3" you create the runningTotal linked list directly in Sum. You give to the first level Sum only the "Head" of the Running Total.
In "version 4" instead of padding the shorter LL, you pass a parameter on the number of digits to skip from the longest LL (this is the most difficult passage).
There is another possibility, much more complex, but that doesn't require to pre-count the length of the lists. It uses two recursive functions:
The first recursive function simply traverses left and right while both are present. If both finishes at the same time then you can simply roll-back as in the previous example.
If one of them finishes before the other, then you use another recursive function like this (the initial value of *extraDigits is 1):
void SaveRemainingDigits(const Digit *remaining, int *extraDigits, int **buffer)
{
int currentDigit = *extraDigits - 1;
*extraDigits = *extraDigits + 1;
if (remaining->Next)
{
SaveRemainingDigits(remaining->Next, extraDigits, buffer);
}
else
{
*buffer = (int*)malloc(sizeof(int) * extraDigits);
}
(*buffer)[currentDigit] = remaining->Dt;
}
when this function finally returns, we have a scratchpad from where to extract the digits and the length of the scratchpad
The innermost level of our first recursive function has now to sum its current digit of the shortest linked list with the last digit of the scratchpad and put the current digit of the longest linked list in the scratchpad in place of the digit just used. Now you unroll your recursive function and you use the scratchpad as a circular array. When you finish unrolling, then you add elements to the runningTotal linked list taking them directly from the scratchpad.
As I've said, it's a little complex, but in 1-2 hours I could write it down as a program.
An example (without carry)
1 2 3 4
6 5
you recurse the first two elements. So you have
1-6 (in the first level)
2-5 (in the second level)
Now you see that the second list is finished and you use the second function.
3 (extraDigit enters as 0, is modified to 1. currentDigit = 0)
4 (extraDigit enters as 1, is modified to 2. currentDigit = 1.
malloc of 2 elements,
buffer[currentDigit] = 4 => buffer[1] = 4)
unroll and we return to the previous row
3 (currentDigit = 0
buffer[currentDigit] = 3 => buffer[0] = 3)
Now we return to the previous function
2-5 (in the second level,
with a lengthBuffer == 2,
we set index = length(buffer) - 1
currentDigitTotal = 5 + buffer[index] => currentDigitTotal = 5 + 4
buffer[index] = 2 => buffer[1] = 2;
index = (index - 1 + lengthBuffer) % lengthBuffer => index = 0
1-6 (in the first level,
with a lengthBuffer == 2,
index = 0,
currentDigitTotal = 6 + buffer[index] => currentDigitTotal = 6 + 3
buffer[index] = 1 => buffer[0] = 1;
index = (index - 1 + lengthBuffer) % lengthBuffer => index = 1
now we exited the recursive function.
In an external function we see that we have a buffer.
We add its elements to the head of the total.
Our Linked list now is 9-9 and our buffer is 1,2 with index 1
for (int i = 0; i < lengthBuffer; i++)
{
runningTotal.AddHead(buffer(index));
index = (index - 1 + lengthBuffer) % lengthBuffer
}
I will approach this problem in something like this
Let's suppose the 2 lists are :
1->2->7->6->4->3 and
5->7->2
The sum is 1->2->7 + Sum(6->4->3, 5->7->2)
Now we make a function that take 2 lists of same size and returns their sum
which will be something like
list1->val + list2->val + Sum(list1->next, list2->next)
with base case if(list1->next == NULL) return list1->val+list2->val;
Note :: we can handle the carry in next pass easily or you can handle that in our sum function itself
So after all this our ans will be 1->2->7->11->11->5
then recursively do %10 and take carry and add it to previous value.
so final ans will be 1->2->8->2->1->5
I would have created a node like *head or *tail to store the address of the node that I started from, then iterate through the list making sure im not back at my start point. This doesn't require to to have to count the length of each, which sounds inefficient.
As for the recursiveness just do this check at the top of the function and return (node->value + myfunct(node->prev)); It'd be more efficient given you're doing the math once.
The lists "1, 2, 9" and "1, 3" each represent the numbers "129" and "13", in which case the sum is "142".
Using recursion
Compute the length of each list.
If the lengths differ, pad the shortest with zeroes at the beggining.
Iterate over the lists recursively, returning: a) the carry number if any, or zero otherwise, and b) the tail of the list.
In pseudocode:
def sum_lists_rec(a, b, start_a, start_b, length_a, length_b):
"""Returns a pair of two elements: carry and the tail of the list."""
if the end of the lists:
return (0, empty_list)
result = sum_lists_rec(a+1, b+1, start_a+1, start_b+1, length_a, length_b)
carry = (a[0] + b[0] + result[0]) / 10
digit = (a[0] + b[0] + result[0]) % 10
return (carry, [digit] ++ result[1])
def sum_lists1(a, b):
length_a = length(a)
length_b = length(b)
if length_a < length_b:
a = [0, 0, ..., (length_b - length_a)] ++ a
else if length_b < length_a:
b = [0, 0, ..., (length_a - length_b)] ++ b
result = sum_lists_rec(a, b, length_a, length_b, 0, 0)
if result[0] != 0:
return [result[0]] ++ result[1]
else:
return result[1]
As an alternative, you can use a stack:
Compute the length of each list.
If the lengths differ, pad the shortest with zeroes at the beggining.
Push each digit of both lists on the stack.
Pop the stack until is empty, creating the new list.