I was trying to solve the 3 sum problem in cpp.
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int size = nums.size();
vector<vector<int>> result;
for (int i = 0; i < size - 2; ++i) {
for (int j = i + 1; j < size - 1; ++j) {
for (int k = j + 1; k < size; ++k) {
if (sumToZero(i, j, k, nums)) {
vector<int> newComb = vectorify(i, j, k, nums);
//printComb(newComb);
if (!exist(newComb, result)) {
//cout << "not exist" << endl;
result.push_back(newComb);
} else {
//cout << "exist" << endl;
}
}
}
}
}
return result;
}
bool sumToZero(int i, int j, int k, vector<int>& nums) {
return nums[i] + nums[j] + nums[k] == 0;
}
vector<int> vectorify(int i, int j, int k, vector<int>& nums) {
vector<int> result;
result.push_back(nums[i]);
result.push_back(nums[j]);
result.push_back(nums[k]);
return result;
}
void printComb(vector<int>& input) {
cout << input[0] << input[1] << input[2] << endl;
}
bool isSameComb(vector<int>& a, vector<int> b) {
for (int i = 0; i < b.size(); ++i) {
if (a[0] == b[i]) {
b.erase(b.begin() + i);
}
}
for (int i = 0; i < b.size(); ++i) {
if (a[1] == b[i]) {
b.erase(b.begin() + i);
}
}
for (int i = 0; i < b.size(); ++i) {
if (a[2] == b[i]) {
b.erase(b.begin() + i);
}
}
return b.empty();
}
bool exist(vector<int>& niddle, vector<vector<int>>& haystack) {
int size = haystack.size();
for (int i = 0; i < size; ++i) {
if (isSameComb(niddle, haystack[i])) {
return true;
}
}
return false;
}
};
However, this solution exceeded the time limit. I cannot think of the source of extra complexity. Can someone help me point out where am I doing extra computation?
You can be in O(n²) with something like:
std::vector<std::vector<int>> threeSum(std::vector<int>& nums) {
std::sort(nums.begin(), nums.end());
std::vector<std::vector<int>> res;
for (auto it = nums.begin(); it != nums.end(); ++it) {
auto left = it + 1;
auto right = nums.rbegin();
while (left < right.base()) {
auto sum = *it + *left + *right;
if (sum < 0) {
++left;
} else if (sum > 0) {
++right;
} else {
res.push_back({*it, *left, *right});
std::cout << *it << " " << *left << " " << *right << std::endl;
++left;
++right;
}
}
}
return res;
}
Demo
I let duplicate handling as exercise.
The source of extra complexity is the third loop, which brings time complexity of your code to O(n3).
Key observation here is that once you have two numbers, the third number is fixed, so you do not need to loop around to find it: use hash table to see if it's there or not in O(1). For example, if your first loop looks at value 56 and your second loop looks at value -96, the third value must be 40 in order to yield zero total.
If the range of numbers is reasonably small (say, -10000..10000) you can use an array instead.
This would bring time complexity to O(n2), which should be a noticeable improvement on timing.
A couple of possibilities:
First, construct a hash table of all entries in the vector up front, then remove the third loop. Inside the second loop, simply check whether -nums[i] - nums[j] exists in the hash table. That should bring your time complexity from O(n3) back to something closer to O(n2).
Second, function calls aren't free though an optimiser can sometimes improve that considerably. There's no performance reason why you should be calling a function to check if three numbers add to zero so you could replace:
if (sumToZero(i, j, k, nums)) {
with:
if (nums[i] + nums[j] == -nums[k]) {
Of course, this is rendered moot if you adopt the first suggestion.
Third, don't check and insert the possible result every time you get one. Just add it to the vector no matter what. Then, at the end, sort the vector and remove any duplicates. That should hopefully speed things up a bit as well.
Fourth, there's quite possibly a performance hit for using a vector for the potential result when an int[3] would do just as well. Vectors are ideal if you need something with a variable size but, if both the minimum and maximum size of an array-type collection is always going to be a fixed value, raw arrays are fine.
But perhaps the most important advice is measure, don't guess!
Make sure that, after each attempted optimisation, you test to see whether it had a detrimental, negligible, or beneficial effect. A test suite of various data sets, and automating the process, will make this much easier. But, even if you have to do it manually, do so - you can't improve what you can't measure.
Here is my solution that finds all unique triplets in O(n^2) run-time.
class Solution {
public: vector<vector<int>> threeSum(vector<int>& nums) {
int len = nums.size();
if(len<3) return {};
sort(nums.begin(), nums.end());
vector<vector<int>> retVector;
int target, begin, end;
int i=0;
while(i < len - 2)
{
int dup; // to find duplicates entries
target = -nums[i];
begin = i + 1; end = len - 1;
while (begin < end)
{
if (nums[begin] + nums[end] < target) begin++;
else if (nums[begin] + nums[end] > target) end--;
else
{
retVector.push_back({nums[i], nums[begin], nums[end]});
// its time to remove duplicates
dup=nums[begin];
do begin++; while(nums[begin] == dup); // removing from front
dup=nums[end];
do end--; while(nums[end] == dup); // removing from back
}
}
dup=nums[i];
do i++; while(nums[i] == dup) ; // removing all ertries same as nums[i]
}
return retVector;
}
};
Related
I'm trying to answer a question on leetcode https://leetcode.com/problems/palindromic-substrings/. I know the passing solution is an O(N^2) solution with dynamic programming. All the solutions I've seen have used a bottom-up approach. I tried to use a top-down approach and I thought I also accomplished O(N^2) but the online judge is giving me time limit exceeded error at the final test case which made me unsure if my implementation is indeed O(N^2). Can someone please tell me the correct big O of the below code?
bool dfs(string s, int start, int end, string curWord, int &count, unordered_map<string, int> &map)
{
if (start >= end)
{
return true;
}
string st = to_string(start) + " , " + to_string(end);
if (map.find(st) != map.end())
return map[st];
if (s[start] == s[end] && dfs(s, start + 1, end - 1, curWord, count, map))
{
count++;
map[st] = true;
}
else
{
map[st] = false;
}
return map[st];
}
int countSubstrings(string s)
{
string word = "";
int count = 0;
unordered_map<string, int> map;
for (int i = 0; i < s.length(); i++)
{
for (int j = s.length() - 1; j > i; j--)
{
dfs(s, i, j, word, count, map);
}
}
return count + s.length();
}
I'm trying to make a program that requires nested loops to work properly.
But the number of nested loops depend on the number of character the user inputs also the character to output.
This is my code so far.
#include<iostream>
using namespace std;
int main(){
string str;
cout<<"Enter some string: ";
cin>>str;
// for two characters
for(int i = 0; i < 2; i++){
for(int j = 0; j < 2 ; j++){
cout<<str[i]<<str[j]<<endl;
}
};
// for four characters
for(int i = 0; i<4; i++){
for(int j=0;j<4;j++){
for(int k =0;k<4;k++){
for(int z=0;z<4;z++)
cout<<str[i]<<str[j]<<str[k]<<str[z]<<endl;
}
}
}
return 0;
}
So, is there any way to solve this issue.
You need to do it dynamically:
std::vector<unsigned int> offsets(s.size());
bool isContinue;
do
{
for(auto offset : offsets)
{
std::cout << s[offset];
}
std::cout << std::endl;
isContinue = false;
for(auto offset = offsets.rbegin(); offset != offsets.rend(); ++offset)
{
if(++*offset < s.size())
{
isContinue = true;
break;
}
*offset = 0;
}
}
while(isContinue);
The idea behind is like upcounting numbers (decimally): Once you've reached 9, you increment next digit. Alike, each offset in the vector stands for one loop variable, on 'overflow', increment next offset, and as soon as most significant offset 'overflows', we are done.
High performance variant (using goto, sparing one comparison and the condition variable):
std::vector<unsigned int> offsets(s.size());
NEXT:
for(auto offset : offsets)
{
std::cout << s[offset];
}
std::cout << std::endl;
for(auto offset = offsets.rbegin(); offset != offsets.rend(); ++offset)
{
if(++*offset < s.size())
goto NEXT;
*offset = 0;
}
There are a couple basic ways to do that looping.
The first is the explicit one: you need to use an array of indexes instead of a single variable for the loop index. Then at each step you increment the last index and when that gets past the limit you reset it and increment the previous one:
int n = str.size(); // Get rid of unsigned
std::vector<int> index(n);
for(;;) {
// Generate output
for (int i=0; i<n; i++) {
std::cout << str[index[i]];
}
std::cout << std::endl;
// Increment
int i = n-1; // start from last index
while (i>=0 && index[i] == n-1) {
// I-th index has reached the end of the string, flip over to 0
index[i] = 0;
--i;
}
if (i == -1) break; // all of them returned to 0... that's all, folks
index[i] += 1;
}
The second way is using recursion, for example with a function accepting the partial string being built as argument and that if this prefix is not complete loops over the string and calls itself passing an extended prefix:
std::function<void(const std::string&)> proc = [&](const std::string& prefix) {
if (prefix.size() == str.size()) {
// Prefix is complete, just output result
std::cout << prefix << std::endl;
} else {
// Extend the prefix and call yourself for the nested loops
for (int j=0; j<n; j++) {
proc(prefix + str[j]);
}
}
};
proc("");
The recursive approach is more compact but takes some time to become comfortable and it can be problematic in certain cases.
A different way avoiding nested loops be to use simple counting and math... it's easy to write a function that returns the n-th string you're looking for without looping over the previous ones...
for (int i=0,loops=pow(n, n); i<loops; i++){
std::string s = "";
int k = i;
for (int j=0; j<n; j++) {
s = str[k % n] + s;
k /= n;
}
std::cout << s << std::endl;
}
Let's fold all your N nested loops into one nested loop. First, we need N indices, which will be incremented properly:
class Multiindex
{
public:
Multiindex(int size, int last_) : idx(size,0), last(last_) {}
void inc()
{
for (int i = idx.size() - 1; i >= 0; --i) {
if (idx[i] == last - 1) {
idx[i] = 0;
if (i == 0) complete = true;
}
else {
++idx[i];
break;
}
}
}
const auto& getIdx() const { return idx; }
const auto isComplete() const { return complete; }
private:
std::vector<int> idx;
int last;
bool complete = false;
};
It's a minimal example of a multiindex class. You also may write a decrement method or use a vector of last indices, if you need different indices in your nested loop.
Now everything is ready to replace your nested loop:
std::string s;// From user
Multiindex midx(s.length(), s.length());
while (!midx.isComplete()) { // Your nested loop
const auto& idx = midx.getIdx();
for (int i = 0; i < idx.size(); ++i) { // Replacement for cout << s[i] << s[j] << ... << s[z] << endl;
std::cout << s[idx[i]];
}
std::cout << std::endl;
midx.inc();
}
Homework: I'm just stumped as hell. I have algorithms set up, but I have no idea how to code this
Just to be clear you do not need arrays or to pass variables by reference.
The purpose of the project is to take a problem apart and using Top-Down_Design or scratch pad method develop the algorithm.
Problem:
Examine the numbers from 2 to 10000. Output the number if it is a Dual_Prime.
I will call a DualPrime a number that is the product of two primes. Ad where the two primes are not equal . So 9 is not a dual prime. 15 is ( 3 * 5 ) .
The output has 10 numbers on each line.
My Algorithm set-up
Step 1: find prime numbers.:
bool Prime_Number(int number)
{
for (int i = 2; i <= sqrt(number); i++)
{
if (number % 1 == 0)
return false;
}
return true;
}
Step 2: store prime numbers in a array
Step 3: Multiply each array to each other
void Multiply_Prime_Numbers(int Array[], int Size)
{
for (int j = 0; j < Size- 1; j++)
{
Dual_Prime[] = Arr[j] * Arr[j + 1]
}
}
Step 4: Bubble sort
void Bubble_Sort(int Array[], int Size) // Sends largest number to the right
{
for (int i = Size - 1; i > 0; i--)
for (int j = 0; j < i; j++)
if (Array[j] > Array[j + 1])
{
int Temp = Array[j + 1];
Array[j + 1] = Array[j];
Array[j] = Temp;
}
}
Step 5: Display New Array by rows of 10
void Print_Array(int Array[], int Size)
{
for (int i = 0; i < Size; i++)
{
cout << Dual_Prime[i] << (((j % 10) == 9) ? '\n' : '\t');
}
cout << endl;
}
I haven't learned dynamic arrays yet,
Although dynamic arrays and the sieve of Eratosthenes are more preferable, I tried to write minimally fixed version of your code.
First, we define following global variables which are used in your original implementation of Multiply_Prime_Numbers.
(Please check this post.)
constexpr int DP_Size_Max = 10000;
int DP_Size = 0;
int Dual_Prime[DP_Size_Max];
Next we fix Prime_Number as follows.
The condition number%1==0 in the original code is not appropriate:
bool Prime_Number(int number)
{
if(number<=1){
return false;
}
for (int i = 2; i*i <= number; i++)
{
if (number % i == 0)
return false;
}
return true;
}
In addition, Multiply_Prime_Numbers should be implemented by double for-loops as follows:
void Multiply_Prime_Numbers(int Array[], int Size)
{
for (int i = 0; i < Size; ++i)
{
for (int j = i+1; j < Size; ++j)
{
Dual_Prime[DP_Size] = Array[i]*Array[j];
if(Dual_Prime[DP_Size] >= DP_Size_Max){
return;
}
++DP_Size;
}
}
}
Then these functions work as follows.
Here's a DEMO of this minimally fixed version.
int main()
{
int prime_numbers[DP_Size_Max];
int size = 0;
for(int j=2; j<DP_Size_Max; ++j)
{
if(Prime_Number(j)){
prime_numbers[size]=j;
++size;
}
}
Multiply_Prime_Numbers(prime_numbers, size);
Bubble_Sort(Dual_Prime, DP_Size);
for(int i=0; i<DP_Size;++i){
std::cout << Dual_Prime[i] << (((i % 10) == 9) ? '\n' : '\t');;
}
std::cout << std::endl;
return 0;
}
The Sieve of Eratosthenes is a known algorithm which speeds up the search of all the primes up to a certain number.
The OP can use it to implement the first steps of their implementation, but they can also adapt it to avoid the sorting step.
Given the list of all primes (up to half the maximum number to examine):
Create an array of bool as big as the range of numbers to be examined.
Multiply each distinct couple of primes, using two nested loops.
If the product is less than 10000 (the maximum) set the corrisponding element of the array to true. Otherwise break out the inner loop.
Once finished, traverse the array and if the value is true, print the corresponding index.
Here there's a proof of concept (implemented without the OP's assignment restrictions).
// Ex10_TwoPrimes.cpp : This file contains the 'main' function. Program execution begins and ends there.
#include "pch.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void Homework_Header(string Title);
void Do_Exercise();
void Sieve_Of_Eratosthenes(int n);
void Generate_Semi_Prime();
bool Semi_Prime(int candidate);
bool prime[5000 + 1];
int main()
{
Do_Exercise();
cin.get();
return 0;
}
void Do_Exercise()
{
int n = 5000;
Sieve_Of_Eratosthenes(n);
cout << endl;
Generate_Semi_Prime();
}
void Sieve_Of_Eratosthenes(int n)
{
// Create a boolean array "prime[0..n]" and initialize
// all entries it as true. A value in prime[i] will
// finally be false if i is Not a prime, else true.
memset(prime, true, sizeof(prime));
for (int p = 2; p*p <= n; p++)
{
// If prime[p] is not changed, then it is a prime
if (prime[p] == true)
{
// Update all multiples of p
for (int i = p * p; i <= n; i += p)
prime[i] = false;
}
}
}
bool Semi_Prime(int candidate)
{
for (int index = 2; index <= candidate / 2; index++)
{
if (prime[index])
{
if (candidate % index == 0)
{
int q = candidate / index;
if (prime[q] && q != index)
return true;
}
}
}
return false;
}
void Generate_Semi_Prime()
{
for (int i = 2; i <= 10000; i++)
if (Semi_Prime(i)) cout << i << "\t";
}
I wanted to do an implementation of Merge Sort in C++. I didn't look at concrete examples because I wanted to try out for myself. And here is what I came up with using vectors:
int *mergeSort(int *a, int n) {
//some debugging info for me
cout << "Merge Sort called with: ";
for(int i = 0; i < n; i++){
cout << *(a + i) << " ";
}
cout << " and size: " << n << endl;
//base case
if (n == 1) {
return a;
}
//spliting the arrays
vector<int> firstArray(a, a + n/2);
vector<int> secondArray(a + n/2, a + n);
int *firstResultPointer = mergeSort(&(firstArray[0]), firstArray.size());
vector<int> resultFirst(firstResultPointer, firstResultPointer + n/2);
int *secondResultPointer = mergeSort(&(secondArray[0]), secondArray.size());
vector<int>resultSecond(secondResultPointer, secondResultPointer + n / 2);
vector<int> resultArray(n);
int i = 0;
int j = 0;
while (i + j < n) {
//when exit the size of the vector
if(firstArray.size() <= i){
while(j < secondArray.size()){
resultArray[(i + j)] = secondArray[j];
j++;
}
break;
}
else if (secondArray.size() <= j){
while(i < firstArray.size()){
resultArray[(i + j)] = firstArray[i];
i++;
}
break;
}
else {
//normal case merge
if (firstArray[i] < secondArray[j]) {
resultArray[(i + j)] = firstArray[i];
i++;
}
else {
resultArray[(i + j)] = secondArray[j];
j++;
}
}
}
return &(resultArray[0]);
}
a is a pointer to the vector and n is the length of the same vector. I had quite a lot of trouble in the merging because it would leave the vector and start using 0. I think I fixed that based on my debugging. However, when I debug after I get to the lowest level and then starting going back up it just starts jumping all over the place and I cannot follow it. Using cout I printed to see what arguments are passed to the merge sort and they seem to be correct. Can anyone tell me where the problem is?
I have a question about singly-linked list in C++.
An integer array[0..n] is called symmetric if array[0] = array[n], array[1] = array[n-1], ...
For example: 1 2 3 4 5 4 3 2 1
So, is there any way to check the symmetry of an integer singly-linked list?
I've thought about copying the value of them downto an array then check the symmetry of this array but I think it is not good because the featured of link list will be lost.
If by "simple-linked" you actually mean singly linked, then you have to copy half of them - whether on the stack using recursion or to an array.
bool is_symmetric(Node* p, int n)
{
Value values[n / 2]; // use alloca or std::vector if your compiler doesn't support
for (int i = 0; i < n / 2; ++i, p = p->next)
values[i] = p->value;
if ((n + 1) % 2) p = p->next; // for odd number of elements, middle one's ok
for (; i >= 0; --i, p = p->next)
if (values[i] != p->value)
return false;
return true;
}
Note: I haven't tested this, and it might have an error or two, but the general idea's there....
If it's doubly linked, it's even easier - iterate half way then iterate in both directions doing the comparisons.
The classic way is to fold over the list and push elements on a stack until half way, then pop from the stack and compare with remaining elements.
bool isPalindrome(forward_list<int> &l){
forward_list<int> stack;
auto it = l.begin();
int len = 0;
int i = 0;
while (it != l.end()){
++len;
++it;
}
if (len <= 1)
return true;
it = l.begin();
while (i < (len / 2)) {
stack.push_front(*it);
++i;
++it;
}
if ((len % 2) == 1)
++it;
while (!stack.empty()){
if (stack.front() != *it)
return false;
stack.pop_front();
++it;
}
return true;
}
bool test_good(const int i){
int j = i / 2;
forward_list<int> l;
for (int k = 0; k < j; k++){
l.push_front(k);
}
if (i % 2 == 1){
l.push_front(j);
}
for (int k = j-1; k >= 0; k--){
l.push_front(k);
}
return isPalindrome(l);
}
bool test_bad(const int i){
forward_list<int> l;
for (int k = 0; k < i; k++){
l.push_front(k);
}
l.push_front(i);
l.push_front(i+1);
return !isPalindrome(l);
}
int main(){
for (int i = 0; i < 20; i++){
cout << "test for " << i << "...";
if (test_good(i))
cout << "ok...";
else return i;
if (test_bad(i))
cout << "ok." << endl;
else return i;
}
return 0;
}
I used a forward_list to implement the stack, rather than using the dedicated std::stack template.
Also, note that the problem is trickier when using generic lists of T, since you don't necessarily want to instantiate copies of values in the list when pushing on the stack, but you can't push references to values of primitive types (like char or int). For that problem, you would have to provide two different templated implementations, which would be enable_ifed according to what T is. You would probably also add the comparison operator to the template.