for a while now I've been trying to get this code to work to partition (as if preparing for quicksort) the indexes of substring suffixes, and while it's close I'm not getting what I'm expecting. I was wondering if a fresh set of eyes may help.
int partition(const string &S, vector<int> &indices, int low, int high, int pivotIndex)
{
int i = low;
int j = high - 1;
swap(indices[high], indices[pivotIndex]);
while (i <= j)
{
while (i < high && !lessThan(S, S[i], S[indices[high]]))
i++;
while (j >= low && lessThan(S, S[j], S[indices[high]]))
j--;
if (i < j)
{
int temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
i++;
j--;
}
}
swap(indices[high], indices[i]);
return i;
}
Indices is simply a vector of 0, 1, 2, ..., n of same size as string S.
And here's the program I wrote for lessThan just so you know what I'm working with:
bool lessThan(const string &S, int first, int second)
{
int counter = (int)S.length() - ((first <= second) ? second : first);
for (int i = 0; i <= counter; ++i)
{
if (S[first + i] != S[second + i])
{
if (S[first + i] < S[second + i])
{
return true;
}
else
{
return false;
}
}
}
if (first < second)
{
return false;
}
else
{
return true;
}
}
lessThan seems to work just fine when I test it separately, so I don't think it's the issue, but maybe it is.
Whenever I test, with say the string "abracadabra", and setting the pivotIndex to 4, I expect to get "0 1 8 3 10 5 7 4 2 9 6" as my output but I instead get "0 1 8 3 7 5 4 10 2 9 6". Close, but not quite. Can anyone spot my mistake?
(P.S. I know I could probably use substr() or some other solution to do lessThan easier, but I'm trying to do it without allocating extra memory, my focus is on the partition function)
edit: I figured it out. Complete error on my side. Check below for answer
I was an idiot, input to lessThan was supposed to be given two ints. I instead gave it two chars from S. Also swapped which lessThan call the ! was on. I think I was just up too late programming and blame this all on sleep deprivation.
Fixed Code:
int partition(const string &S, vector<int> &indices, int low, int high, int pivotIndex)
{
int i = low;
int j = high - 1;
swap(indices[high], indices[pivotIndex]);
while (i <= j)
{ //This right here
while (i < high && lessThan(S, indices[i], indices[high]))
i++;
while (j >= low && !lessThan(S, indices[j], indices[high]))
j--;
if (i < j)
{
swap(indices[i], indices[j]);
i++;
j--;
}
}
swap(indices[high], indices[i]);
return i;
}
Related
How to count comparisons in selectionsort?
terms:
when the statements you perform to find the maximum value is 'true'
then count comparison.
The value to get the maximum value is held at the first element in the array, not at random.
I try with C
variable count position change - no work
new variable 'first' , first=sort[MAX] insert first for loop, - no work
#include <stdio.h>
int main() {
int sort[10000], i, n, MAX, temp, count;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &sort[i]);
}
for (MAX = 0; MAX < n; MAX++)
for (i = MAX + 1; i < n; i++) {
if (sort[MAX] > sort[i]) {
count++;
temp = sort[MAX];
sort[MAX] = sort[i];
sort[i] = temp;
}
}
printf("%d ", count);
return 0;
}
Sample Input
10
0 7 1 6 7 7 6 6 5 4
Sample Output
17
EDIT: new code:
#include <stdio.h>
#define SWAP(x, y, temp) ( (temp)=(x), (x)=(y), (y)=(temp) )
int count = 0;
void selection_sort(int list[], int n) {
int i, j, least, temp;
for (i = 0; i < n - 1; i++) {
least = i;
for (j = i + 1; j < n; j++) {
if (list[j] < list[least]) {
least = j;
count++;
}
}
SWAP(list[i], list[least], temp);
}
}
int main() {
int list[10000], i, n;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &list[i]);
};
selection_sort(list, n);
printf("%d", count);
}
how about this? why this code didn't move too?
You aren't counting the right thing, this code
if(sort[MAX]>sort[i])
{
count++;
temp=sort[MAX];
sort[MAX]=sort[i];
sort[i]=temp;
}
counts the times that two numbers are swapped. But you want to count comparisons so it should be this
count++;
if(sort[MAX]>sort[i]) // this is what we are counting
{
temp=sort[MAX];
sort[MAX]=sort[i];
sort[i]=temp;
}
Another problem is that you don't give count an initial value of zero
int sort[10000],i,n,MAX,temp,count;
should be
int sort[10000],i,n,MAX,temp,count = 0;
how to count comparison selectionsort?
Your definition of the term is oddly worded, but it seems to be intended to focus on the essential comparisons of the algorithm, as opposed to comparisons performed incidentally for other purposes, or inside library functions. That is, in the implementation you present (whose correctness I do not evaluate), you're to count each evaluation of sort[MAX]>first, but not MAX<n or i<n.
You appear to be using variable count for that purpose, but you are counting only comparisons that evaluate to true. My interpretation of the problem, based both on the wording presented and on my general expectations for such a problem, is that every evaluation of sort[MAX]>first should be counted, regardless of the result. That would be achieved by lifting the expression count++ out of the if block, but leaving it inside the inner enclosing for loop.
Of course, as #john observes, you do need to initialize count to 0 before beginning to sort. You might luck into getting that by accident, but the initial value of a local variables without an initializer is indeterminate (at least) until a value is assigned.
i try with c variable count position change - no work
new variable 'first' , first=sort[MAX] insert first for loop, - no work
Even with the misplacement of your increment to count, if your sort were in fact working then you would expect to see some counts for most inputs. That you don't is a good sign that your sort in fact does not work correctly. I would suggest outputting also the the sorted results so that you can debug the details of the sort algorithm.
You could abstract out the comparison into a function or macro that also increments a counter. The macro approach could be
#define GT(x,y,counter) (counter++, (x) > (y) ? 1 : 0)
...
if ( GT( sort[MAX], sort[i], count ) == 1 )
{
// perform swap
}
whereas the function approach would be
int gt( int x, int y, int *counter )
{
(*counter)++;
if ( x > y )
return 1;
return 0;
}
...
if ( gt( sort[MAX], sort[i], &count ) == 1 )
{
// perform swap
}
You are counting the number of swaps, not the number of comparisons.
Here is a corrected without a global variable and a few extra checks:
#include <stdio.h>
#define SWAP(x, y, temp) ((temp) = (x), (x) = (y), (y) = (temp))
int selection_sort(int list[], int n) {
int count = 0;
int i, j, least, temp;
for (i = 0; i < n - 1; i++) {
least = i;
for (j = i + 1; j < n; j++) {
count++;
if (list[j] < list[least]) {
least = j;
}
}
SWAP(list[i], list[least], temp);
}
return count;
}
int main() {
int list[10000], i, n, count;
if (scanf("%d", &n) != 1 || n > 10000)
return 1;
for (i = 0; i < n; i++) {
if (scanf("%d", &list[i]) != 1)
return 1;
}
count = selection_sort(list, n);
printf("%d\n", count);
return 0;
}
Not however that your algorithm will always perform the same number of comparisons for any set of n values: n * (n - 1) / 2 comparisons, and since you do not test of i != least, it will perform n - 1 swaps.
I've tried searching for an answer on StackOverflow and googled multiple times. I'm not really sure what exactly is wrong with the code. When I run it on Eclipse Luna, it just says "solution.exe has stopped working". Can anyone help me find out what's wrong here? Or give me a way to find out for myself?
This is my code:
#include <fstream>
#include <iostream>
#include <vector>
using namespace std;
long mergeCountInv(long list[],long tmp[],long left,long mid,long right);
long countInv(long list[],long tmp[],long left,long right);
long mergeCountInv(long list[],long tmp[],long left,long mid,long right) {
long i = 0,j = mid + 1,k = 0;
long count = 0;
while(i < mid && j < right) {
if(list[i] <= list[j]) {
tmp[k++] = list[i++];
}
else if(list[i] > list[j]) {
tmp[k++] = list[j++];
count++;
}
}
while(i < mid) {
tmp[k++] = list[i++];
}
while(j < right) {
tmp[k++] = list[j++];
}
return count;
}
long countInv(long list[],long tmp[],long left,long right) {
long k = 0,mid;
if(right == 1) return 0;
else {
mid = (left + right)/2;
k = countInv(list,tmp,left,mid) + countInv(list,tmp,mid + 1,right) + mergeCountInv(list,tmp,left,mid,right);
}
return k;
}
int main() {
long list[100001];
long i,x=0;
///////////////FILE HANDLING////////////////////////////////
ifstream fin;
fin.open("IntegerArray.txt");
while (!fin.eof()) {
fin >> i;
list[x] = i;
x++;
}
fin.close();
////////////////////////////////////////////////////////////
long size = sizeof(list)/sizeof(long) - 1;
long *tmp = new long[size];
cout<<countInv(list,tmp,0,size);
delete []tmp;
return 0;
}
These are the contents of "IntegerArray.txt":
6
3
5
4
2
1
There are actually going to be 100000 integers in the file, but I'm trying it out with a smaller test case first.
I would appreciate your help! Thanks.
The recursion never terminates if right is greater than 1, as your base case for the recursion is right == 1 while you have one recursive call that passes right unmodified.
That is, countInv(x,y,l,r) calls countInv(x,y,amidpoint,r), which calls countInv(x,y,anothermidpoint,r), and so on, until you're stuck in countInv(x,y,r-1,r) forever.
Exactly how to fix it depends on what the code is supposed to do, but you most likely want a base case that involves left as well as right.
I'm trying to write a recursive function that checks if two arrays have the same elements even if they aren't sorted, but I I can't change the arrays and I can't copy them or use a third/fourth arrays and it has to be recursive, lastly, I can't change the signature of the function.
So now I have to get rid of overwrite(A2, len, i); because that's destroying A2, but I don't see any way to do it and still have a working function... can I have a hint on how to do it? Maybe there's a way to save the elements of A2 by swapping them and then by the end of the recursion to restore them?
In short the algorithm below does a linear search of the last element of A1 in A2, if it's found, overwrite it and continue, this is done so the algorithm won't pick the same element twice, reaching the stopping condition means all the elements are there thus it will return true, otherwise will return false.
bool foo(int A1[], int A2[], int len){//both arrays are size len
int i;
bool found = false;
if (len == 0)return true;//stopping condition for recursion
else{
for (i = 0; i < len && !found; i++)//linear search
if (A1[len - 1] == A2[i]){
overwrite(A2, len, i);//this function shifts back the whole array
found = true;
}
if (found == false) return false;
else foo(A1, A2, len - 1);
}
}
Sample i/o:
A1: 3 2 1
A2: 1 2 3
True
A1: 3 2 3
A2: 1 2 3
False
A solution could be:
find what is the maximum value M in in A1 and how many times it appears
check if it's the same for A2, including the count
find what is the maximum value M1 among all values smaller than M and how many times is present in A1
check if it's the same for A2, including the count
find what is the maximum value M2 among all values smaller than M1 and how many times is present in A1
check if it's the same for A2, including the count
repeat this way until the counter for A1 and A2 is zero or is different
in code:
bool checkSame(int *A1, int *A2, int len) {
struct Same {
static bool check(int *A1, int *A2, int len, int limit) {
int index1=-1, count1=0;
for (int i=0; i<len; i++) {
if (A1[i] <= limit) {
if (index1==-1 || A1[i] > A1[index1]) {
index1 = i;
count1 = 1;
} else if (A1[i] == A1[index1]) {
count1++;
}
}
}
int index2=-1, count2=0;
for (int i=0; i<len; i++) {
if (A2[i] <= limit) {
if (index2==-1 || A2[i] > A2[index2]) {
index2 = i;
count2 = 1;
} else if (A2[i] == A2[index2]) {
count2++;
}
}
}
if (index1 == -1 && index2 == -1) return true;
if (count1 != count2 || count1 == 0 ||
A1[index1] != A2[index2]) return false;
return check(A1, A2, len, A1[index1]-1);
}
};
return Same::check(A1, A2, len, INT_MAX);
}
This algorithm is O(n^2) in time (worst case: arrays are identical and all values unique) and requires constant space if the compiler supports tail call optimization.
The following is a chart for the time needed in ms from 0 to 3000 elements on my PC.
Note that however all this is not a decent solution for the problem but just an exercise in futility. A real solution of course would need more context as there are different criteria for optimality, but I'd probably go for a closed hash table... adding elements while processing A1 and removing elements processing A2 (the removal will fail at some point if and only if the arrays are different):
bool checkSame2(int *A1, int *A2, int len) {
std::vector<int> ht(len, -1), next(len, -1);
for (int i=0; i<len; i++) {
int k = (unsigned)A1[i]*69069 % len;
next[i] = ht[k]; ht[k] = i;
}
for (int i=0; i<len; i++) {
int k = (unsigned)A2[i]*69069 % len;
int prev=-1,p=ht[k];
while (p!=-1 && A1[p] != A2[i]) {
prev = p; p = next[p];
}
if (p == -1) return false;
if (prev == -1) ht[k] = next[p]; else next[prev] = next[p];
}
return true;
}
The execution time for this solution is the purple line touching the N axis in the previous chart (hard to tell with this scale but it's linear + noise, as expected).
Just out of curiosity I also tried what would be the solution if "optimal" means just getting something working that is not hideous:
bool checkSame3(int *A1, int *A2, int len) {
std::map<int, int> counts;
for (int i=0; i<len; i++) counts[A1[i]]++;
for (int i=0; i<len; i++) {
if (--counts[A2[i]] < 0) return false;
}
return true;
}
and this is, unsurprisingly, about 30-40 times slower than the hand-coded hash table version on my PC (but of course still much faster than the recursive version).
Here is a solution that works given all your requirements. It rearranges the arrays, and then un-rearranges them. It uses recursion, uses no additional arrays, and does not change the function signature.
bool foo(int A1[], int A2[], int len){
int i;
if (len == 0){
return true;
} else {
for (i = len - 1; i >= 0; i--){
if (A1[len - 1] == A2[i]){
A2[i] = A2[len - 1];
A2[len - 1] = A1[len - 1];
bool result = foo(A1, A2, len - 1);
A2[len - 1] = A2[i];
A2[i] = A1[len - 1];
return result;
}
}
return false;
}
}
If you are allowed to temporarily change the arrays, provided that you restore them before the last recursive call has returned, you can swap the matching element in A2 with the element at index len - 1 before the recursive call, and swap them back afterwards. Since the recursive call will only look at the index range 0 through len - 2, the matching element will not be considered.
Actually i am trying to solve SPOJ Problem:
[SPOJ] http://www.spoj.com/problems/SQRBR/ . I came up with recurence to solve it but i am not getting how to do memoisation. Any suggestion on how to memoisation for given problem will be helpful. my code is giving correct answer , but it is giving TLE in spoj Here my code :
#include <iostream>
#include <cstdio>
using namespace std;
void balancedParen(int n, int open, int position, int close, char str[], string s, long long int &counter) {
if(close == n) {
str[pos] = '\0';
printf("%s\n", str);
counter++;
return;
}
if(s[position] == '(' ) {
if(open <= n-1) {
str[position] = '(';
balancedParen(n, open+1, position+1, close, str, s, counter);
}
} else {
if(open < n) {
str[position] = '(';
balancedParen(n, open+1, position+1, close, str, s, counter);
}
if(open > close) {
str[position] = ')';
balancedParen(n, open, position+1, close+1, str, s, counter);
}
}
return ;
}
int main() {
int a[100], n, k, i;
long long counter = 0;
int testCases;
scanf("%d", &testCases);
while(testCases--) {
scanf("%d", &n);
scanf("%d", &k);
char str[100];
string s = "..........................................................................";
for(i = 0; i < k; i++) {
scanf("%d", &a[i]);
s[a[i]-1] = '(';
}
balancedParen(n, 0, 0, 0, str, s, counter);
printf("%lld\n", counter);
counter = 0;
}
return 0;
}
I can think of one relatively simple and possibly significant optimization.
First, instead of making the "counter" a reference, make it the return value of the function. Hear me out for a bit here.
Now say the positions you're given are "1, 7, 15". Instead of recursively going "1, 2, 3, 4, 5, 6, 7", you can be a little tricky and go to 7 in one step.
You just need to count the number of permutations which can be used to go between 1 and 7, for every possible number of opening parens (in this case, 3, 4, 5 and 6)
For example, how many ways exist to have 3 opening parens between 1 and 7?
[[[]]]
[[][]]
[][][]
[[]][]
[][[]]
5 permutations (unless I missed one). So you can add 5*balancedParen(n, open+3, position+6, close+3, str, s, counter) to your result. And do a similar thing for 4, 5, and 6 opening parens.
Of course you'd need to write another function (recursive approach seems simplest) to find that number "5". But the advantage is that the total number of function calls is now (calls to get from 1 to 7) + (calls to get from 7 to 15), rather than (calls to get from 1 to 7) * (calls to get from 7 to 15).
Here is some code which should work using the algorithm I described:
int countPermutations(int unclosed, int length, int toOpen)
{
if (toOpen > length) // impossible to open this many, not enough length
return 0;
int toClose = length-toOpen;
if (toClose - toOpen > unclosed)
return 0; // No possibilities; not enough open parens to fill the length
if (toOpen == 0 || toOpen == length)
return 1; // Only one possibility now
int ret = 0;
if (toOpen > 0) // Count permutations if we opened a paren here
ret += countPermutations(unclosed+1, length-1, toOpen-1);
if (unclosed > 0) // Count permutations if we closed a paren here
ret += countPermutations(unclosed-1, length-1, toOpen);
return ret;
}
int countNLengthSolutions(int n, int unclosed, int position, int *positions, int remainingPositions)
{
if (n % 2 != 0)
return 0; // must be a length divisible by 2
if (position > n)
return 0;
if (n-position < unclosed)
return 0; // too many open parens, no way to complete within length
if (remainingPositions == 0)
{
// Too many open parens to close by the time we get to length N?
if ((n - position) < unclosed)
return 0;
else // Say we have 4 open and a length of 10 to fill; we want (10-4)/2 = 3 more open parens.
return countPermutations(unclosed, n-position, (n-position - unclosed)/2);
}
else
{
int ret = 0;
int toFill = *positions - position - 1;
for (int openParens = 0; openParens <= toFill; openParens++)
{
int permutations = countPermutations(unclosed, toFill, openParens);
if (permutations > 0)
ret += permutations*countNLengthSolutions(n, unclosed+(2*openParens-toFill)+1, position+toFill+1, positions+1, remainingPositions-1);
}
return ret;
}
}
I may have a bug somewhere, I didn't really spend the time to check, but I verified it works for all the sample input.
I'm trying to solve a problem which is something like this:
I'm given n numbers (1<=n<=10^5).I have to write the sum of all numbers on its left which are smaller than the current number and repeat the process for all n numbers.Then I have to find the sum of all previously obtained sum's.(Each number N,0<=N<=10^6).
For example,
1 5 3 6 4
less1 less5 less3 less6 less4
(0) + (1) + (1)+(1+5+3)+(1+3)
0 + 1 + 1 + 9 + 4
= 15
A trivial solution for this problem will be to run two loops and for each of the given number find sum of all the numbers less than that number and finally give the sum of those sum's as output.The time complexity is O(n^2).
I think a better O(nlogn) solution for this problem using Binary Indexed Tree(Fenwick Tree).
For each number I'll add each of the number in a global array a and perform two obvious operations of BIT.I think the time complexity of this algorithm is O(nlogn) which if true is obviously better than the previous O(n^2).
I have implemented the code in C++.
#include<iostream>
#include<cstdio>
using namespace std;
#define max 1000001
long int a[max];
void add(long int v,int idx){
while(idx<max){
a[idx] += v;
idx += (idx & -idx);
}
}
long int sum(int idx){
long int s=0;
while(idx>0){
s += a[idx];
idx -= (idx & -idx);
}
return s;
}
int main()
{
int t;
scanf("%d",&t);
for(int w=0;w<t;w++){
int n;
scanf("%d",&n);
for(int i=0;i<max;i++)
a[i]=0;
int arr[n];
for(int i=0;i<n;i++)
scanf("%d",&arr[i]);
long long res=0;
for(int i=0;i<n;i++){
if(arr[i]!=0){
add(arr[i],arr[i]);
res += (sum(arr[i]-1));
}
}
printf("%lld\n",res);
}
return 0;
}
I have two questions:
First, am I doing it correct? / Is my logic correct?
Second, if I'm right about the time complexity to be O(nlogn) then why does it run slow? Can you help me with any further optimizations?
Got Accepted with 1.41 seconds.At same time I have updated my finally accepted code.Any suggestion for optimization ?
Based on the comments I tried my own function for faster I/O but still it's not going my way.This is my function for fast I/O :
inline int read(){
char c=getchar_unlocked();
int n=0;
while(!(c>='0' && c<='9'))
c=getchar_unlocked();
while(c>='0' && c<='9'){
n=n*10 + (c-'0');
c=getchar_unlocked();
}
return n;
}
This is the link to the problem :
http://www.spoj.pl/problems/DCEPC206/
If there is anyone who is abled to solve it,please let me know.
Thanks.
I think your approach is a good one. I've played around with this a wee bit and haven't come up with anything generally better than what you have.
There are a couple of bugs in your code though. There are a few places suffering from integer overflow. You should change to:
long long a[max];
and
long long sum(int idx){
long long s=0;
The more apparent bug is that you're summing numbers which are less than or equal to the current number. To fix this issue, you could add a second global array for tracking the count of each value:
int b[max];
...
...
for(int i=0;i<max;i++)
a[i]=b[i]=0;
...
...
res += (sum(idx)-(++b[idx]*val));
There may be a more efficient way to fix that bug, but overall it still seems like a fast solution.
Here is another approach: the problem is similar to counting inversions, except you have to sum the elements responsible for generating inversions. We can solve this using merge sort. Modify the merge function like this:
merge(left, middle, right, array)
temp = new array
k = 0, i = left, j = middle + 1
while i <= middle and j <= right
if array[i] < array[j]
temp[k++] = array[i]
// array[i] is also smaller than all array[j+1], ..., array[right]
globalSum += array[i] * (right - j + 1)
else
// same as the classical function
Intuitively, I would say a recursive mergesort is slower than a BIT solution, but who knows? Give it a try.
Edit: This gets AC:
#include<stdio.h>
#include <iostream>
using namespace std;
#define max 100001
int n;
long long res = 0;
int temp[max];
int arr[max];
void merge(int left, int m, int right)
{
int k = 0;
int i = left, j = m + 1;
while (i <= m && j <= right)
if (arr[i] < arr[j])
{
temp[k++] = arr[i];
res += (long long)(right - j + 1) * arr[i++];
}
else
temp[k++] = arr[j++];
while (j <= right)
temp[k++] = arr[j++];
while (i <= m)
temp[k++] = arr[i++];
for (int i = 0; i < k; ++i)
arr[left + i] = temp[i];
}
void sort(int left, int right)
{
if (left < right)
{
int m = left + (right - left) / 2;
sort(left, m);
sort(m + 1, right);
merge(left, m, right);
}
}
int main()
{
int t;
scanf("%d", &t);
for(int w=0;w<t;w++)
{
scanf("%d", &n);
for(int i=0;i<n;i++)
scanf("%d", &arr[i]);
res=0;
sort(0, n - 1);
printf("%lld\n",res);
}
return 0;
}