Related
Below is the code I used for comparing:
// Example program
#include <iostream>
#include <string>
#include <vector>
#include <chrono>
using namespace std::chrono;
using namespace std;
bool existHelperArrayVersion(string &word, int i, int u_i, int u_j, vector<vector<char>>& Board)
{
if(i>=word.length())
{
return true;
}
else
{
bool answer = false;
if(Board[u_i][u_j] == word[i])
{
char temp = Board[u_i][u_j];
Board[u_i][u_j] = '?';
int row_len = Board.size();
int col_len = Board[0].size();
// Uses Array
int row_offset[4]={0, 0, 1, -1};
int col_offset[4]={1, -1, 0, 0};
for(int k=0; k<4; k++)
{
int v_i = u_i + row_offset[k];
int v_j = u_j + col_offset[k];
if( !(0 >v_i || v_i >= row_len || 0>v_j || v_j >= col_len) && (Board[v_i][v_j] != '?'))
answer |= existHelperArrayVersion(word, i+1, v_i, v_j, Board);
}
if(i+1 == word.length())
answer |= true;
Board[u_i][u_j] = temp;
}
return answer;
}
}
bool existHelperVectorVersion(string &word, int i, int u_i, int u_j, vector<vector<char>>& Board)
{
if(i>=word.length())
{
return true;
}
else
{
bool answer = false;
if(Board[u_i][u_j] == word[i])
{
char temp = Board[u_i][u_j];
Board[u_i][u_j] = '?';
int row_len = Board.size();
int col_len = Board[0].size();
//Uses Vectors
vector<int> row_offset = {0, 0, 1, -1};
vector<int> col_offset = {1, -1, 0, 0};
for(int k=0; k<4; k++)
{
int v_i = u_i + row_offset[k];
int v_j = u_j + col_offset[k];
if( !(0 >v_i || v_i >= row_len || 0>v_j || v_j >= col_len) && (Board[v_i][v_j] != '?'))
answer |= existHelperVectorVersion(word, i+1, v_i, v_j, Board);
}
if(i+1 == word.length())
answer |= true;
Board[u_i][u_j] = temp;
}
return answer;
}
}
bool exist(vector<vector<char>>& board, string word, int option)
{
if(option == 0)
cout << "----ARRAY------\n";
else if(option == 1)
cout << "---VECTOR-----\n";
bool answer = false;
for(int i=0; i<board.size(); i++)
{
for(int j=0; j<board[i].size(); j++)
{
if(option == 0)
answer |= existHelperArrayVersion( word, 0, i, j, board);
else if(option == 1)
answer |= existHelperVectorVersion( word, 0, i, j, board);
if(answer)
{
return true;
}
}
}
return false;
}
int main()
{
string word = "AAAAAAAAAAAAAAB";
vector<vector<char>> board = {{'A','A','A','A','A','A'},
{'A','A','A','A','A','A'},
{'A','A','A','A','A','A'},
{'A','A','A','A','A','A'},
{'A','A','A','A','A','A'},
{'A','A','A','A','A','A'}};
auto start = high_resolution_clock::now();
bool answer = exist(board, word, 0);
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << "Time taken when Using C-style Array : " << duration.count() << " microseconds" << endl;
start = high_resolution_clock::now();
answer = exist(board, word, 1);
stop = high_resolution_clock::now();
duration = duration_cast<microseconds>(stop - start);
cout << "Time taken when Using STL vector : " << duration.count() << " microseconds" << endl;
}
output
----ARRAY------
Time taken when Using C-style Array : 112931 microseconds
---VECTOR-----
Time taken when Using STL vector : 330641 microseconds
As you can see the array version of my function performs on average 3 times faster than that of its Vector version. (I ran it multiple times and got similar results)
Question:
Are vectors really that slow compared to arrays?
I thought their performance was supposed to be on par.
This is the URL I run it on an online environment http://cpp.sh/2ubur
vector<int> row_offset = {0, 0, 1, -1};
vector<int> col_offset = {1, -1, 0, 0};
this causes 2 heap allocations of data (almost) every time the function is called.
int row_offset[4]={0, 0, 1, -1};
int col_offset[4]={1, -1, 0, 0};
this does not cause 2 heap allocations of data (almost) every time the function is called.
std::vector<int> foo = {1,2,3} is similar to int* foo = new int[]{1,2,3}, not int foo[] = {1,2,3} in creation costs.
std::array<int, 3> foo={1,2,3}
is the std library version of "fixed size buffer with data in it". std::vector is a dynamically sized buffer.
Here is a live example where I swapped std::vector for std::array, and changed the C-array version to dynamically create and destroy the arrays. You'll notice the time swaps.
You create your vectors in your function, so each function invocation allocates their memory anew and destroys them at the end of the function. An array is instead constantly baked into your program.
Try moving your vectors out of your function, then both functions are equally fast: http://cpp.sh/53t2z
If you replace:
vector<int> row_offset = { 0, 0, 1, -1 };
vector<int> col_offset = { 1, -1, 0, 0 };
with:
static vector<int> row_offset; row_offset = { 0, 0, 1, -1 };
static vector<int> col_offset; col_offset = { 1, -1, 0, 0 };
the difference will be much less. With the second version the vectors won't be constructed from scratch each time.
This is only for demonstration purposes, and it's not an example to follow.
At any rate the best approach here is to replace std::vector with std::array since you have fixed sizes here.
BTW on http://cpp.sh the version with std::array even seems to be somewhat faster than the raw array version.
The other day, I wrote a console game of Tic-Tac-Toe in c++ for my son. He wanted me to add a computer, and I ended us using the minimax algorithm for the first time. I did some quick testing, but really just gave my laptop to my son as soon as it was printing stuff, who played with it for a couple minuets. I looked over his sholder once or twice, and noticed that it wasn't playing optimally, iv'e been trying to debug it, but I can't see where it goes wrong. I tried getting rid of alpha beta prunning, but that did not change anything.
For context, on the board the computer is -1, blank is 0, and the player is 1.
Here is the minimax function:
int minimax(int board[9], int depth, int alpha, int beta, bool isMaxizimaizingPlayer)
{
bool found = false;
for (int i = 0; i < 9; i++)
{
if (board[i] == 0)
{
found = true;
}
}
if (!found)
{
return eval(board);
}
if (depth == 0 || eval(board) != 0)
{
return eval(board);
}
if (isMaxizimaizingPlayer)
{
int maxEval = -2;
for (int spot = 0; spot < 9; spot++)
{
if (board[spot] == 0)
{
board[spot] = 1;
int e = minimax(board, depth - 1, alpha, beta, false);
if (e > maxEval)
{
maxEval = e;
}
//if (beta < alpha)
//{
// break;
//}
board[spot] = 0;
}
}
return maxEval;
}
else {
int minEval = 2;
for (int spot = 0; spot < 9; spot++)
{
if (board[spot] == 0)
{
board[spot] = -1;
int e = minimax(board, depth - 1, alpha, beta, true);
if (e < minEval)
{
minEval = e;
}
//if (beta < alpha)
//{
// break;
//}
board[spot] = 0;
}
}
return minEval;
}
}
To be compleate, here is my eval function:
int eval(int board[9])
{
/*horizontial*/
for (int i = 0; i < 3; i++)
{
if (board[i * 3] == board[i * 3 + 1] && board[i * 3 + 2] == board[i * 3] && board[i * 3] != 0)
{
return board[i * 3];
}
}
/*vertical*/
for (int i = 0; i < 3; i++)
{
if (board[i] == board[i + 3] && board[i] == board[i + 6] && board[i] != 0)
{
return board[i];
}
}
/*Both diags*/
if (board[4] != 0) {
if (board[0] == board[4] && board[0] == board[8])
{
return board[4];
}
if (board[2] == board[4] && board[4] == board[6])
{
return board[4];
}
}
return 0;
}
And here is the inital call:
int spot = 0;
int minEval = 2;
for (int i = 0; i < 9; i++)
{
if (board[i] == 0)
{
board[i] = -1;
int score = minimax(board, 3, -2, 2, false);
if (score < minEval) {
minEval = score;
spot = i;
}
board[i] = 0;
}
}
std::cout << "The computer went in spot " << spot + 1 << std::endl;
board[spot] = -1;
printBoard(board);
It looks like you only call minimax with a depth of three, so the algorithm will only look up to three moves ahead, if you want optimal play you need to set the depth to > 9, so that the agent is always looking ahead to the end of the game.
I've been trying to solve this problem (from school) for just about a week now. We're given two numbers, from -(10^100000) to +that.
Of course the simplest solution is to implement written addition, so that's what I did. I decided, that I would store the numbers as strings, using two functions:
int ti(char a) { // changes char to int
int output = a - 48;
return output;
}
char tc(int a) { // changes int to char
char output = a + 48;
return output;
}
This way I can store negative digits, like -2. With that in mind I implemented a toMinus function:
void toMinus(std::string &a) { // 123 -> -1 -2 -3
for (auto &x : a) {
x = tc(-ti(x));
}
}
I also created a changeSize function, which adds 0 to the beginning of the number until they are both their max size + 1 and removeZeros, which removes leading zeros:
void changeSize(std::string &a, std::string &b) {
size_t exp_size = std::max(a.size(), b.size()) + 2;
while (a.size() != exp_size) {
a = '0' + a;
}
while (b.size() != exp_size) {
b = '0' + b;
}
}
void removeZeros(std::string &a) {
int i = 0;
for (; i < a.size(); i++) {
if (a[i] != '0') {
break;
}
}
a.erase(0, i);
if (a.size() == 0) {
a = "0";
}
}
After all that, I created the main add() function:
std::string add(std::string &a, std::string &b) {
bool neg[2] = {false, false};
bool out_negative = false;
if (a[0] == '-') {
neg[0] = true;
a.erase(0, 1);
}
if (b[0] == '-') {
neg[1] = true;
b.erase(0, 1);
}
changeSize(a, b);
if (neg[0] && !(neg[1] && neg[0])) {
toMinus(a);
}
if(neg[1] && !(neg[1] && neg[0])) {
toMinus(b);
}
if (neg[1] && neg[0]) {
out_negative = true;
}
// Addition
for (int i = a.size() - 1; i > 0; i--) {
int _a = ti(a[i]);
int _b = ti(b[i]);
int out = _a + _b;
if (out >= 10) {
a[i - 1] += out / 10;
} else if (out < 0) {
if (abs(out) < 10) {
a[i - 1]--;
} else {
a[i - 1] += abs(out) / 10;
}
if (i != 1)
out += 10;
}
a[i] = tc(abs(out % 10));
}
if (ti(a[0]) == -1) { // Overflow
out_negative = true;
a[0] = '0';
a[1]--;
for (int i = 2; i < a.size(); i++) {
if (i == a.size() - 1) {
a[i] = tc(10 - ti(a[i]));
} else {
a[i] = tc(9 - ti(a[i]));
}
}
}
if (neg[0] && neg[1]) {
out_negative = true;
}
removeZeros(a);
if (out_negative) {
a = '-' + a;
}
return a;
}
This program works in most cases, although our school checker found that it doesn't - like instead of
-4400547114413430129608370706728634555709161366260921095898099024156859909714382493551072616612065064
it returned
-4400547114413430129608370706728634555709161366260921095698099024156859909714382493551072616612065064
I can't find what the problem is. Please help and thank you in advance.
Full code on pastebin
While I think your overall approach is totally reasonable for this problem, your implementation seems a bit too complicated. Trying to solve this myself, I came up with this:
#include <iostream>
#include <limits>
#include <random>
#include <string>
bool greater(const std::string& a, const std::string& b)
{
if (a.length() == b.length()) return a > b;
return a.length() > b.length();
}
std::string add(std::string a, std::string b)
{
std::string out;
bool aNeg = a[0] == '-';
if (aNeg) a.erase(0, 1);
bool bNeg = b[0] == '-';
if (bNeg) b.erase(0, 1);
bool resNeg = aNeg && bNeg;
if (aNeg ^ bNeg && (aNeg && greater(a, b) || bNeg && greater(b, a)))
{
resNeg = true;
std::swap(a, b);
}
int i = a.length() - 1;
int j = b.length() - 1;
int carry = 0;
while (i >= 0 || j >= 0)
{
const int digitA = (i >= 0) ? a[i] - '0' : 0;
const int digitB = (j >= 0) ? b[j] - '0' : 0;
const int sum = (aNeg == bNeg ? digitA + digitB : (bNeg ? digitA - digitB : digitB - digitA)) + carry;
carry = 0;
if (sum >= 10) carry = 1;
else if (sum < 0) carry = -1;
out = std::to_string((sum + 20) % 10) + out;
i--;
j--;
}
if (carry) out = '1' + out;
while (out[0] == '0') out.erase(0, 1);
if (resNeg) out = '-' + out;
return out;
}
void test()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(-std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::max());
for (int i = 0; i < 1000000; ++i)
{
const int64_t a = dis(gen);
const int64_t b = dis(gen);
const auto expected = std::to_string(a + b);
const auto actual = add(std::to_string(a), std::to_string(b));
if (actual != expected) {
std::cout << "mismatch expected: " << expected << std::endl;
std::cout << "mismatch actual : " << actual << std::endl;
std::cout << " a: " << a << std::endl;
std::cout << " b: " << b << std::endl;
}
}
}
int main()
{
test();
}
It can potentially be further optimized, but the main points are:
If the sign of both numbers is the same, we can do simple written addition. If both are negative, we simply prepend - at the end.
If the signs are different, we do written subtraction. If the minuend is greater than the subtrahend, there's no issue, we know that the result will be positive. If, however, the subtrahend is greater, we have to reformulate the problem. For example, 123 - 234 we would formulate as -(234 - 123). The inner part we can solve using regular written subtraction, after which we prepend -.
I test this with random numbers for which we can calculate the correct result using regular integer arithmetic. Since it doesn't fail for those, I'm pretty confident it also works correctly for larger inputs. An approach like this could also help you uncover cases where your implementation fails.
Other than that, I think you should use a known failing case with a debugger or simply print statements for the intermediate steps to see where it fails. The only small differences in the failing example you posted could point at some issue with handling a carry-over.
i've been working on word search algorithm for quite long I think i made it good and decided to test limits. I've created program which makes file as big as I want to. So i made a matrix 10000 * 10000 (10000000 letters) and really long word from top left corner to bottom right corner. Thing is that it works with 4000 * 4000 matrix but then it gets bigger it just crashes. I tried to comment all other checkings for possible location and left the right one and it works perfectly even with 10000 * 10000 matrix but as soon as I add other checks it stops and I have no idea why. Any suggestions?
My code:
#include <iostream> //Might Be:
#include <string> // <----->
#include <fstream> // /-\ (1)/\ /\(3)
#include <new> // | \ /
#include <cstdlib> // | \ /
// | \ /
// | \ /
// | \ /
// \_/ (2)\/ \/(4)
//
using namespace std;
//Loop[4] //Loop[5]
int * Possibles(int Widht, int Height, int Poz, int Poz1, int Leng, int * Possible)
{
if(Poz1 < Widht - Leng + 1) // To right
{
Possible[0] = 1;
}
if(Poz1 >= Leng - 1) // To left
{
Possible[1] = 1;
}
if(Poz <= Height - Leng) // From top to bottom
{
Possible[2] = 1;
}
if(Poz >= Leng) // From bottom to top
{
Possible[3] = 1;
}
if(Poz + Leng <= Height && Poz1 + Leng <= Widht) //(2)
{
Possible[4] = 1;
}
if(Poz + Leng <= Height && Poz1 - Leng + 1 >= 0) //(4)
{
Possible[5] = 1;
}
if(Poz - Leng + 1 >= 0 && Poz1 - Leng + 1 >= 0) //(1)
{
Possible[6] = 1;
}
if(Poz - Leng + 1 >= 0 && Poz1 + Leng <= Widht) //(3)
{
Possible[7] = 1;
}
return Possible;
}
int * Zero(int * Possible)
{
Possible[0] = 0;
Possible[1] = 0;
Possible[2] = 0;
Possible[3] = 0;
Possible[4] = 0;
Possible[5] = 0;
Possible[6] = 0;
Possible[7] = 0;
return Possible;
}
string Next(string * NewMatrix, int Height, int Widht)
{
return NewMatrix[Height].substr(Widht, 1);
}
bool Find(string Word, int Poz, int Poz1, int Look, string Have, string * Matrix, int * Possible, int Backup, int Backup1)
{
if(Have == Word)
{
return true;
return Possible;
}
string NewLet = Word.substr(Look, 1);
if(Possible[0] == 1)
{
if(NewLet == Next(Matrix, Poz, Poz1 + 1))
{
Have += NewLet;
return Find(Word, Poz, Poz1 + 1, Look + 1, Have, Matrix, Possible, Backup, Backup1);
}
else
{
Possible[0] = 0;
Have = Word.substr(0, 1);
return Find(Word, Backup, Backup1, 1, Have, Matrix, Possible, Backup, Backup1);
}
}
if(Possible[1] == 1)
{
if(NewLet == Next(Matrix, Poz, Poz1 - 1))
{
Have += NewLet;
return Find(Word, Poz, Poz1 - 1, Look + 1, Have, Matrix, Possible, Backup, Backup1);
}
else
{
Possible[1] = 0;
Have = Word.substr(0, 1);
return Find(Word, Backup, Backup1, 1, Have, Matrix, Possible, Backup, Backup1);
}
}
if(Possible[2] == 1)
{
if(NewLet == Next(Matrix, Poz + 1, Poz1))
{
Have += NewLet;
return Find(Word, Poz + 1, Poz1, Look + 1, Have, Matrix, Possible, Backup, Backup1);
}
else
{
Possible[2] = 0;
Have = Word.substr(0, 1);
return Find(Word, Backup, Backup1, 1, Have, Matrix, Possible, Backup, Backup1);
}
}
if(Possible[3] == 1)
{
if(NewLet == Next(Matrix, Poz - 1, Poz1))
{
Have += NewLet;
return Find(Word, Poz - 1, Poz1, Look + 1, Have, Matrix, Possible, Backup, Backup1);
}
else
{
Possible[3] = 0;
Have = Word.substr(0, 1);
return Find(Word, Backup, Backup1, 1, Have, Matrix, Possible, Backup, Backup1);
}
}
if(Possible[4] == 1)
{
if(NewLet == Next(Matrix, Poz + 1, Poz1 + 1))
{
Have += NewLet;
return Find(Word, Poz + 1, Poz1 + 1, Look + 1, Have, Matrix, Possible, Backup, Backup1);
}
else
{
Possible[4] = 0;
Have = Word.substr(0, 1);
return Find(Word, Backup, Backup1, 1, Have, Matrix, Possible, Backup, Backup1);
}
}
if(Possible[5] == 1)
{
if(NewLet == Next(Matrix, Poz + 1, Poz1 - 1))
{
Have += NewLet;
return Find(Word, Poz + 1, Poz1 - 1, Look + 1, Have, Matrix, Possible, Backup, Backup1);
}
else
{
Possible[5] = 0;
Have = Word.substr(0, 1);
return Find(Word, Backup, Backup1, 1, Have, Matrix, Possible, Backup, Backup1);
}
}
if(Possible[6] == 1)
{
if(NewLet == Next(Matrix, Poz - 1, Poz1 - 1))
{
Have += NewLet;
return Find(Word, Poz - 1, Poz1 - 1, Look + 1, Have, Matrix, Possible, Backup, Backup1);
}
else
{
Possible[6] = 0;
Have = Word.substr(0, 1);
return Find(Word, Backup, Backup1, 1, Have, Matrix, Possible, Backup, Backup1);
}
}
if(Possible[7] == 1)
{
if(NewLet == Next(Matrix, Poz - 1, Poz1 + 1))
{
Have += NewLet;
return Find(Word, Poz - 1, Poz1 + 1, Look + 1, Have, Matrix, Possible, Backup, Backup1);
}
else
{
Possible[7] = 0;
Have = Word.substr(0, 1);
return Find(Word, Backup, Backup1, 1, Have, Matrix, Possible, Backup, Backup1);
}
}
return false;
}
string Diro(int * Possible)
{
string Dir;
bool Next = true;
if(Possible[0] == 1 && Next == true)
{
Dir = " From right to left";
Next = false;
}
if(Possible[1] == 1 && Next == true)
{
Dir = " From left to right";
Next = false;
}
if(Possible[2] == 1 && Next == true)
{
Dir = " From top to bottom";
Next = false;
}
if(Possible[3] == 1 && Next == true)
{
Dir = " From bottom to top";
Next = false;
}
if(Possible[4] == 1 && Next == true)
{
Dir = " ";
Next = false;
}
if(Possible[5] == 1 && Next == true)
{
Dir = " ";
Next = false;
}
if(Possible[6] == 1 && Next == true)
{
Dir = " ";
Next = false;
}
if(Possible[7] == 1 && Next == true)
{
Dir = " ";
Next = false;
}
return Dir;
}
int main()
{
int Height = 0, Widht = 0, Numb = 0;
int Loop[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
int * Possible = new int[8];
string Dir, Search, Tempo, Temp;
ifstream Data("C:/Users/Magician/AppData/Local/VirtualStore/Program Files (x86)/CodeBlocks/MakeMaze/Files/Maze.txt");
Data >> Widht >> Height;
string * NewMatrix = new string[Height];
while(Loop[7] < Height)
{
Tempo = "";
Loop[8] = 0;
while(Loop[8] < Widht)
{
Data >> Temp;
Tempo += Temp;
Loop[8]++;
}
NewMatrix[Loop[7]] = Tempo;
Loop[7]++;
}
Data >> Numb;
string * Words = new string[Numb];
while(Loop[2] < Numb)
{
Data >> Words[Loop[2]];
Loop[2]++;
}
Data.close();
while(Loop[3] < Numb)
{
Search = Words[Loop[3]].substr(0, 1);
Loop[4] = 0;
while(Loop[4] < Height)
{
Loop[5] = 0;
while(Loop[5] < Widht)
{
if(NewMatrix[Loop[4]].substr(Loop[5], 1) == Search)
{
Zero(Possible);
Possibles(Widht, Height, Loop[4], Loop[5], Words[Loop[3]].size(), Possible);
if(Find(Words[Loop[3]], Loop[4], Loop[5], 1, Search, NewMatrix, Possible, Loop[4], Loop[5]))
{
cout << Words[Loop[3]] << " At: " << Loop[4] + 1 << " collumn, symbol " << Loop[5] + 1 << " " << Diro(Possible) << endl;
Loop[5] = Widht;
Loop[4] = Height;
}
}
Loop[5]++;
}
Loop[4]++;
}
Loop[3]++;
}
delete [] Possible;
delete [] Words;
delete [] NewMatrix;
return 0;
}
If you didn't understood what I wrote before: when I comment every if(Possible[] == )
except for if(Possible[5] == 1) in function Find() algorithm works then all allowed it doesn't. I've tried with 100 * 100 matrix with a lot of words to find and everything's ok.
One condition in Possibles is incorrect:
/* INCORRECT: Should be [ Poz >= Leng - 1 ] */
if(Poz >= Leng) // From bottom to top
{
Possible[3] = 1;
}
But this one is only a logical error and should not cause segmentation faults.
It looks like you have encountered a stack overflow.
Let's do simple calculation. For 10000 * 10000 matrix and word length of 10000, if you start calling Find() at the top left of the matrix, then three directions are possible. In worst case, Find() will traverse about 10000*3 elements. Note in Func() there are 3 string instances (sizeof(string) == 24 in 32bit VC2013), plus various integers. The size of a single frame could easily exceed 100 bytes. Since you are using recursive calls, this could lead to a stack usage of at least 10000 * 3 * 100 = 3000000bytes = approx. 3M.
This number is not very large, but enough for a stack overflow since Windows has a default stack size of 1M. (http://msdn.microsoft.com/en-us/library/8cxs58a6.aspx)
Advice for improvements
This is my used pattern to solve this kinds of matrix traversal problems.
First, define an constant array to hold offsets for movements (Moore neighborhood):
const int delta[8][2] = {
{ 1, 0 }, { 1, 1 }, { 0, 1 }, { -1, 1 },
{ -1, 0 }, { -1, -1 }, { 0, -1 }, { 1, -1 }
};
Second, use a single for to check for all directions:
int initial_x = .., initial_y = ..;
for (int dir = 0; dir < 8; dir++) {
for (int count = 0; count < WORD_LENGTH; count++) {
int current_x = initial_x + delta[dir][0] * count;
int current_y = initial_y + delta[dir][1] * count;
if (IS_INVALID(current_x, current_y)) {
break;
}
}
}
Last, insert various code and flags to complete the program.
Another hint: you can use char type to get and compare a single character in a string (Use word[idx] to get idxth character of word). This could be substantially faster than using substr.
I am writing a C++ program that would find and print the first longest
ascending or descending continuous subsequence for a vector of integers. For example,
given a vector with
4, 2, 1, 2, 3, 4, 3, 5, 1, 2, 4, 6, 5
return 1,2,3,4
My code is as follows:
But, I do not know how to return the first optimal solution.
For example, the above sequence has 1, 2, 4, 6 which is also 4 long.
But, we only need to return 1,2,3,4.
bool findLong(const vector<int> v)
{
if (v.size() <1)
return false;
if (v.size() == 1){
cout << v[0] << endl;
return true;
}
vector::const_iterator itr_left, itr_right;
itr_left = v.begin();
itr_right = v.begin()+1;
bool ascending_flag ;
int counter =0;
if (*itr_right > *(itr_right-1)){
bool ascending_flag = true;
++ascending_counter;
}
else{
bool ascending_flag = false;
++descending_counter;
}
int longest = INT_MIN;
Vector<int>::iterator longest_left = v.begin(), longest_right =v.begin();
++itr_right;
while (itr_right != v.end())
{
if (ascending_flag && *itr_right > *(itr_right-1))
++ascending_counter;
if (!ascending_flag&& *itr_right < *(itr_right-1))
++descending_counter;
if (ascending_flag&& *itr_right < *(itr_right-1))
{
if (ascending_counter > longest )
{
longest = ascending_counter;
longest_left = itr_left;
longest_right = itr_right;
}
itr_left = itr_right;
ascending_counter = 0 ;
ascending_flag = false;
}
if (ascending_flag && *itr_right > *(itr_right-1))
{
if (descending_counter > longest )
{
longest = descending_counter;
longest_left = itr_left;
longest_right = itr_right;
}
itr_left = itr_right;
descending_counter = 0 ;
ascending_flag = true;
}
++itr_right;
}
for_each( longest_left , longest_right, print);
cout << endl;
}
Void print(int i)
{
cout << i << " , " ;
}
Any comments are welcome !
Thanks !
You have lot of typo in your code:
You hide the initialization of ascending_flag
Your length count seems incorrect.
Following should work (as long as there aren't two neighbours with same values).
bool findLong(const vector<int>& v)
{
if (v.empty())
return false;
if (v.size() == 1) {
cout << v[0] << endl;
return true;
}
vector<int>::const_iterator itr_left = v.begin();
vector<int>::const_iterator itr_right = v.begin() + 1;
vector<int>::const_iterator longest_left = itr_left;
vector<int>::const_iterator longest_right = itr_right;
bool ascending_flag = (*itr_right > *(itr_right - 1));
for (++itr_right; itr_right != v.end(); ++itr_right)
{
if (ascending_flag ^ (*itr_right < *(itr_right - 1)))
{
if (itr_right - itr_left > longest_right - longest_left)
{
longest_left = itr_left;
longest_right = itr_right;
}
itr_left = itr_right - 1;
ascending_flag = !ascending_flag;
}
}
for_each(longest_left, longest_right, print);
cout << endl;
return true;
}
Here are some thoughts:
If function is named "findX()", it should return X (say, pointer to the first element of the sequence or NULL, or index of the first element or -1). If function prints X, it should be named "printX()".
It's not clear whether you need ascending or strictly ascending sequence (i.e. is (1, 2, 2, 3) good for you or not).
You overcomplicate things. If you need first sequence, you just use reverse iterators and go from end to beginning, like this (I don't use iterators, but it should be clear how to include them):
int maxLength=1, currentUp=1, currentDown=1; //Last element is sequence of 1 element
size_t result = v.length()-1;
for(size_t i = v.length()-1; i!=0; --i){
if(v[i-1] > v[i]) {
currentDown++; currentUp=0;
} else if(v[i-1] < v[i]) {
currentUp++; currentDown=0;
} else {
//Not clear what should happen, change may be needed
currentUp++; currentDown++;
}
if(maxLength <= max(currentUp, currentDown)) {
result = i-1;
maxLength = max(currentUp, currentDown);
}
}
return result;
Well, for starters, your function will always return true.
if (v.size() <1)
return false;
if (v.size() == 1)
cout << v[0] << endl;
return true;
should probably be
if (v.size() <1) {
return false;
} else if (v.size() == 1) {
cout << v[0] << endl;
return true;
}