C++, multiset, Time complexity - c++

#include<bits/stdc++.h>
int main()
{
int n;
std::cin>>n;
char st[n];
getchar();
for (int i=0; i<n; ++i)
st[i]=getchar();
std::multiset<char> s;
int pos1=0,pos2=n-1;
for (char c:st) s.insert(c);
for (int i=0; i<n; ++i) {
if (s.count(st[i])==1) {
pos1=i;
break;
} else s.erase(s.find(st[i]));
}
for (int i=n-1; i>=0; --i) {
if (s.count(st[i])==1) {
pos2=i;
break;
} else s.erase(s.find(st[i]));
}
std::cout<<pos2-pos1+1;
}
I have just summit this code to CodeForces system, and it fail the TL (2s), i dont know why, because n constrain is 10^5. And my code work with O(nlogn). Can u guys help me? Thanks <3<3. Link of problem here : http://codeforces.com/problemset/problem/701/C

Indeed, your algorithm is O(nlogn) but this is not a garantee to not exceed a time limit. Remember that the multiplication constant for a big-O complexity may be too big to keep it under a certain time limit.
You are using a multiset only for keeping a count for each type of Pokemon. You lose much time to erase from that multiset and count again from it. You can do much faster than the multiset:
By using a map to keep the count for each type and to update it
Better yet, since pokemon types are encoded in single chars, you can use an array of 256 elements to keep track of the count. This way you can avoid the "log(n)" complexity of multiset (and map). Here's a refactored version of your code that should run much faster, and moreover it runs in O(n).
int main()
{
int n;
std::cin >> n;
std::vector<char> st(n);
std::array<int, 256> count; // we could also use a map if we had a bigger set of types...
// the way you read the input can also be speeded-up,
// but I want to focus on speeding up the algorithm
getchar();
for (int i=0; i<n; ++i) {
st[i]=getchar(); ++count[st[i]];
}
int pos1=0,pos2=n-1;
for (int i=0; i < n; ++i) {
if (count[st[i]] == 1) {
pos1 = i;
break;
} else --count[st[i]];
}
for (int i=n-1; i>=0; --i) {
if (s.count(st[i])==1) {
pos2=i;
break;
} else --count[st[i]];
}
std::cout<<pos2-pos1+1;
}

Related

How to sort an Array in increasing order after squaring each element?

My code can get the correct output but it's exceeding the time limit. How can I improve it?
class Solution {
public:
vector<int> sortedSquares(vector<int>& A) {
//sorting based on absolute values
for(int i=0;i!=A.size();++i){
for(int j=0;j!=A.size();++j){
if(abs(A[i])<abs(A[j])){
int temp=0;
temp=A[i];
A[i]=A[j];
A[j]=temp;
}
}
}
//squaring each element
for(auto &k: A){
k*=k;
}
return A;
}
};
Whoever gave you this task played a bit of a trick on you. Your goal is to end up with sorted array of squares -- so why not do away with squaring first? Do that and you can then omit all calls to abs(). Maybe that will already get you below the time limit.
The second improvement is a bit of a guess, but worth a try. A is not const (can't be or you wouldn't be able to sort it). That means that compiler can make fewer assumptions that would help it optimize your code. For example, it can't know that all calls to A.size() will return the same value. But you know that, so you can optimize that as well.
The third improvement I suspect compiler already does for you, but why not cleanup that anyway. Why would you initialize temp to 0 only to assign it a value in the next line? You can simply initialize it to correct value. Or you could even go as far as using std::swap()...
class Solution {
public:
vector<int> sortedSquares(vector<int>& A) {
// squaring each element
for(auto &k: A){
k*=k;
}
// sorting squares
auto size = A.size();
for(int i=0; i!=size; ++i){
for(int j=0; j!=size; ++j){
if(A[i] < A[j]){
int temp=A[i];
A[i]=A[j];
A[j]=temp;
// or replace this block with std::swap(A[i], A[j])
}
}
}
return A;
}
};

Issues with Sieve of Eratosthenes

I picked up "Programming Principles and Practice using C++", and was doing an early problem involving the Sieve of Eratosthenes, and I'm having unexpected output, but I cannot pin down exactly what the problem is. Here is my code:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> prime;
std::vector<int> nonPrime;
int multiple = 0;
for(int i = 2; i < 101; i++) //initialized to first prime number, i will
// be the variable that should contain prime numbers
{
for(int j = 0; j < nonPrime.size(); j++) //checks i against
// vector to see if
// marked as nonPrime
{
if(i == nonPrime[j])
{
goto outer;//jumps to next iteration if number
// is on the list
}
}
prime.push_back(i); //adds value of i to Prime vector if it
//passes test
for(int j = i; multiple < 101; j++) //This loop is where the
// sieve bit comes in
{
multiple = i * j;
nonPrime.push_back(multiple);
}
outer:
;
}
for(int i = 0; i < prime.size(); i++)
{
std::cout << prime[i] << std::endl;
}
return 0;
}
The question only currently asks me to find prime numbers up to 100 utilizing this method. I also tried using this current 'goto' method of skipping out of a double loop under certain conditions, and I also tried using a Boolean flag with an if statement right after the check loop and simply used the "continue;" statement and neither had any effect.
(Honestly I figured since people say goto was evil perhaps it had consequences that I hadn't foreseen, which is why I tried to switch it out) but the problem doesn't call for me to use modular functions, so I assume it wants me to solve it all in main, ergo my problem of utilizing nested loops in main. Oh, and to further specify my output issues, it seems like it only adds multiples of 2 to the nonPrime vector, but everything else checks out as passing the test (e.g 9).
Can someone help me understand where I went wrong?
Given that this is not a good way to implement a Sieve of Eratosthenes, I'll point out some changes to your code to make it at least output the correct sequence.
Please also note that the indentation you choose is a bit misleading, after the first inner loop.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> prime;
std::vector<int> nonPrime;
int multiple = 0;
for(int i = 2; i < 101; i++)
{
// you can use a flag, but note that usually it could be more
// efficiently implemented with a vector of bools. Try it yourself
bool is_prime = true;
for(int j = 0; j < nonPrime.size(); j++)
{
if(i == nonPrime[j])
{
is_prime = false;
break;
}
}
if ( is_prime )
{
prime.push_back(i);
// You tested 'multiple' before initializing it for every
// new prime value
for(multiple = i; multiple < 101; multiple += i)
{
nonPrime.push_back(multiple);
}
}
}
for(int i = 0; i < prime.size(); i++)
{
std::cout << prime[i] << std::endl;
}
return 0;
}

Fastest way to find if a lot numbers are in multiple intervals

so I have a task. I've been given n numbers and m intervals and I need to figure out how many numbers are in the m i-th interval. I've written some code with a complexity of O(n*m), though I need to optimize it more. Any help?
Code:
#include <bits/stdc++.h>
using namespace std;
int main()
{
cin.tie(0);
ios_base::sync_with_stdio(0);
cout.tie(0);
int n,m,temp,temp1;
vector <pair<int, int>> uogienes;
vector <int> erskeciai;
cin >> n >> m;
for (int i = 0; i< n; i++){
cin>>temp;
erskeciai.push_back(temp);
}
temp = 0;
for (int i = 0; i<m; i++){
cin>> temp >> temp1;
uogienes.push_back(make_pair(temp, temp1));
}
for(int i = 0; i<m; i++){
temp=0;
for(int h = 0; h<n; h++){
if(uogienes[i].first <= erskeciai[h] && uogienes[i].second >= erskeciai[h]){
temp++;
}
}
cout << temp << "\n";
}
return 0;
}
As DAle already noted.
You can first sort the n numbers. A good algorithm, like merge or heap sort, will give you a complexity O(n*log(n)).
After that you need to use search algorithm for both your 'first' and 'second' parts of each interval. Depending on the algorithm, the complexity should be around O(log(n)) - std::lower_bound has complexity of O(log(n)) when working on sorted data, so its good enough. Or that will be O(m*log(n)) for all intervals.
Comparing the result of the search will give you the amount of numbers in each interval.
In total you'll have around O((m+n)*log(n)).

Count number of ways for choosing two numbers in efficient algorithm

I solved this problem but I got TLE Time Limit Exceed on online judge
the output of program is right but i think the way can be improved to be more efficient!
the problem :
Given n integer numbers, count the number of ways in which we can choose two elements such
that their absolute difference is less than 32.
In a more formal way, count the number of pairs (i, j) (1 ≤ i < j ≤ n) such that
|V[i] - V[j]| < 32. |X|
is the absolute value of X.
Input
The first line of input contains one integer T, the number of test cases (1 ≤ T ≤ 128).
Each test case begins with an integer n (1 ≤ n ≤ 10,000).
The next line contains n integers (1 ≤ V[i] ≤ 10,000).
Output
For each test case, print the number of pairs on a single line.
my code in c++ :
int main() {
int T,n,i,j,k,count;
int a[10000];
cin>>T;
for(k=0;k<T;k++)
{ count=0;
cin>>n;
for(i=0;i<n;i++)
{
cin>>a[i];
}
for(i=0;i<n;i++)
{
for(j=i;j<n;j++)
{
if(i!=j)
{
if(abs(a[i]-a[j])<32)
count++;
}
}
}
cout<<count<<endl;
}
return 0;
}
I need help how can I solve it in more efficient algorithm ?
Despite my previous (silly) answer, there is no need to sort the data at all. Instead you should count the frequencies of the numbers.
Then all you need to do is keep track of the number of viable numbers to pair with, while iterating over the possible values. Sorry no c++ but java should be readable as well:
int solve (int[] numbers) {
int[] frequencies = new int[10001];
for (int i : numbers) frequencies[i]++;
int solution = 0;
int inRange = 0;
for (int i = 0; i < frequencies.length; i++) {
if (i > 32) inRange -= frequencies[i - 32];
solution += frequencies[i] * inRange;
solution += frequencies[i] * (frequencies[i] - 1) / 2;
inRange += frequencies[i];
}
return solution;
}
#include <bits/stdc++.h>
using namespace std;
int a[10010];
int N;
int search (int x){
int low = 0;
int high = N;
while (low < high)
{
int mid = (low+high)/2;
if (a[mid] >= x) high = mid;
else low = mid+1;
}
return low;
}
int main() {
cin >> N;
for (int i=0 ; i<N ; i++) cin >> a[i];
sort(a,a+N);
long long ans = 0;
for (int i=0 ; i<N ; i++)
{
int t = search(a[i]+32);
ans += (t -i - 1);
}
cout << ans << endl;
return 0;
}
You can sort the numbers, and then use a sliding window. Starting with the smallest number, populate a std::deque with the numbers so long as they are no larger than the smallest number + 31. Then in an outer loop for each number, update the sliding window and add the new size of the sliding window to the counter. Update of the sliding window can be performed in an inner loop, by first pop_front every number that is smaller than the current number of the outer loop, then push_back every number that is not larger than the current number of the outer loop + 31.
One faster solution would be to first sort the array, then iterate through the sorted array and for each element only visit the elements to the right of it until the difference exceeds 31.
Sorting can probably be done via count sort (since you have 1 ≤ V[i] ≤ 10,000). So you get linear time for the sorting part. It might not be necessary though (maybe quicksort suffices in order to get all the points).
Also, you can do a trick for the inner loop (the "going to the right of the current element" part). Keep in mind that if S[i+k]-S[i]<32, then S[i+k]-S[i+1]<32, where S is the sorted version of V. With this trick the whole algorithm turns linear.
This can be done constant number of passes over the data, and actually can be done without being affected by the value of the "interval" (in your case, 32).
This is done by populating an array where a[i] = a[i-1] + number_of_times_i_appears_in_the_data - informally, a[i] holds the total number of elements that are smaller/equals to i.
Code (for a single test case):
static int UPPER_LIMIT = 10001;
static int K = 32;
int frequencies[UPPER_LIMIT] = {0}; // O(U)
int n;
std::cin >> n;
for (int i = 0; i < n; i++) { // O(n)
int x;
std::cin >> x;
frequencies[x] += 1;
}
for (int i = 1; i < UPPER_LIMIT; i++) { // O(U)
frequencies[i] += frequencies[i-1];
}
int count = 0;
for (int i = 1; i < UPPER_LIMIT; i++) { // O(U)
int low_idx = std::max(i-32, 0);
int number_of_elements_with_value_i = frequencies[i] - frequencies[i-1];
if (number_of_elements_with_value_i == 0) continue;
int number_of_elements_with_value_K_close_to_i =
(frequencies[i-1] - frequencies[low_idx]);
std::cout << "i: " << i << " number_of_elements_with_value_i: " << number_of_elements_with_value_i << " number_of_elements_with_value_K_close_to_i: " << number_of_elements_with_value_K_close_to_i << std::endl;
count += number_of_elements_with_value_i * number_of_elements_with_value_K_close_to_i;
// Finally, add "duplicates" of i, this is basically sum of arithmetic
// progression with d=1, a0=0, n=number_of_elements_with_value_i
count += number_of_elements_with_value_i * (number_of_elements_with_value_i-1) /2;
}
std::cout << count;
Working full example on IDEone.
You can sort and then use break to end loop when ever the range goes out.
int main()
{
int t;
cin>>t;
while(t--){
int n,c=0;
cin>>n;
int ar[n];
for(int i=0;i<n;i++)
cin>>ar[i];
sort(ar,ar+n);
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(ar[j]-ar[i] < 32)
c++;
else
break;
}
}
cout<<c<<endl;
}
}
Or, you can use a hash array for the range and mark occurrence of each element and then loop around and check for each element i.e. if x = 32 - y is present or not.
A good approach here is to split the numbers into separate buckets:
constexpr int limit = 10000;
constexpr int diff = 32;
constexpr int bucket_num = (limit/diff)+1;
std::array<std::vector<int>,bucket_num> buckets;
cin>>n;
int number;
for(i=0;i<n;i++)
{
cin >> number;
buckets[number/diff].push_back(number%diff);
}
Obviously the numbers that are in the same bucket are close enough to each other to fit the requirement, so we can just count all the pairs:
int result = std::accumulate(buckets.begin(), buckets.end(), 0,
[](int s, vector<int>& v){ return s + (v.size()*(v.size()-1))/2; });
The numbers that are in non-adjacent buckets cannot form any acceptable pairs, so we can just ignore them.
This leaves the last corner case - adjacent buckets - which can be solved in many ways:
for(int i=0;i<bucket_num-1;i++)
if(buckets[i].size() && buckets[i+1].size())
result += adjacent_buckets(buckets[i], buckets[i+1]);
Personally I like the "occurrence frequency" approach on the one bucket scale, but there may be better options:
int adjacent_buckets(const vector<int>& bucket1, const vector<int>& bucket2)
{
std::array<int,diff> pairs{};
for(int number : bucket1)
{
for(int i=0;i<number;i++)
pairs[i]++;
}
return std::accumulate(bucket2.begin(), bucket2.end(), 0,
[&pairs](int s, int n){ return s + pairs[n]; });
}
This function first builds an array of "numbers from lower bucket that are close enough to i", and then sums the values from that array corresponding to the upper bucket numbers.
In general this approach has O(N) complexity, in the best case it will require pretty much only one pass, and overall should be fast enough.
Working Ideone example
This solution can be considered O(N) to process N input numbers and constant in time to process the input:
#include <iostream>
using namespace std;
void solve()
{
int a[10001] = {0}, N, n, X32 = 0, ret = 0;
cin >> N;
for (int i=0; i<N; ++i)
{
cin >> n;
a[n]++;
}
for (int i=0; i<10001; ++i)
{
if (i >= 32)
X32 -= a[i-32];
if (a[i])
{
ret += a[i] * X32;
ret += a[i] * (a[i]-1)/2;
X32 += a[i];
}
}
cout << ret << endl;
}
int main()
{
int T;
cin >> T;
for (int i=0 ; i<T ; i++)
solve();
}
run this code on ideone
Solution explanation: a[i] represents how many times i was in the input series.
Then you go over entire array and X32 keeps track of number of elements that's withing range from i. The only tricky part really is to calculate properly when some i is repeated multiple times: a[i] * (a[i]-1)/2. That's it.
You should start by sorting the input.
Then if your inner loop detects the distance grows above 32, you can break from it.
Thanks for everyone efforts and time to solve this problem.
I appreciated all Attempts to solve it.
After testing the answers on online judge I found the right and most efficient solution algorithm is Stef's Answer and AbdullahAhmedAbdelmonem's answer also pavel solution is right but it's exactly same as Stef solution in different language C++.
Stef's code got time execution 358 ms in codeforces online judge and accepted.
also AbdullahAhmedAbdelmonem's code got time execution 421 ms in codeforces online judge and accepted.
if they put detailed explanation to there algorithm the bounty will be to one of them.
you can try your solution and submit it to codeforces online judge at this link after choosing problem E. Time Limit Exceeded?
also I found a great algorithm solution and more understandable using frequency array and it's complexity O(n).
in this algorithm you only need to take specific range for each inserted element to the array which is:
begin = element - 32
end = element + 32
and then count number of pair in this range for each inserted element in the frequency array :
int main() {
int T,n,i,j,k,b,e,count;
int v[10000];
int freq[10001];
cin>>T;
for(k=0;k<T;k++)
{
count=0;
cin>>n;
for(i=1;i<=10000;i++)
{
freq[i]=0;
}
for(i=0;i<n;i++)
{
cin>>v[i];
}
for(i=0;i<n;i++)
{
count=count+freq[v[i]];
b=v[i]-31;
e=v[i]+31;
if(b<=0)
b=1;
if(e>10000)
e=10000;
for(j=b;j<=e;j++)
{
freq[j]++;
}
}
cout<<count<<endl;
}
return 0;
}
finally i think the best approach to solve this kind of problems to use frequency array and count number of pairs in specific range because it's time complexity is O(n).

Insert values from one array to another directly sorted

So what I have to do is insert certain values from one array to another one directly sorted without having to sort them later using BubbleSort or QuickSort or any other method. I can't think of a way to do this... I have to insert them from the biggest value to the smallest one. Here's what I have until now:
void palindroame (int x[100], int y[100]) {
int i=0, j, k=0, aux;
while (x[i]!=0) {
k++; i++;
}
i=0;
for (i=0; i<=k-1; i++) y[i]=0;
for (i=0; i<=k-1; i++) {
if (palindrom(x[i])!=0 && palindrom(x[i+1])!=0)
if (x[i]<x[i+1]) {
aux=x[i+1]; x[i+1]=x[i]; x[i]=aux;
}
} //wrong
for (i=0; i<=k-1; i++) {
if (palindrom(x[i])) y[i]=x[i];
} //wrong
}
Thanks in advance!
The algorithm you need is selection sort, you can use this to sort and copy at the same time.
You can have a look at priority queues:
http://www.cplusplus.com/reference/queue/priority_queue/
Heres an example of a selection sort i have done recently (in which a is a vector)
should give you enough to go on hope it helps, ask questions if u like
for (unsigned int i = 0; i < a.size()-1; i++)
{
int min = i;
for(unsigned int j = i +1; j < a.size(); j++)
{
// If new minimum is found then stores this as the new minimum
if(a[j] < a[min])
{
min = j;
}
}
// Stores the values in the array in ascending order
if (min != i)
{
int temp = a[i];
a[i] = a[min];
a[min] = temp;
}
}
// Returns the array in ascending order
return a;
Edit: just to clarify this is working on a vector that already has values in it in case that wasnt clear but example with code comments i think is enough to help you IMO