I'm taking an Intro to Programming class and a good chunk of the material is drilled into our heads through myProgrammingLab. I'm having a little trouble with the concept of Recursion... It's sort of been hit or miss for me. This particular problem has me stumped. When I submit my code, it offers me
CTest1.cpp: In function 'bool isPalindrome(int*, int)':
CTest1.cpp:9: error: invalid conversion from 'int' to 'int*'
CTest1.cpp:9: error: initializing argument 1 of 'bool isPalindrome(int*, int)'"
as advice, which I can assure you is not very helpful. Lol
I think my main problem is when I get to the actual recursion. I'm aware that something's off, but.. If you could just point me in the right direction, I would very much appreciate it.
A 'array palindrome' is an array which, when its elements are reversed, remains the same (i.e., the elements of the array are same when scanned forward or backward)
Write a recursive, bool-valued function, isPalindrome, that accepts an integer -valued array , and the number of elements and returns whether the array is a palindrome.
An array is a palindrome if: the array is empty (0 elements ) or contains only one element (which therefore is the same when reversed), or the first and last elements of the array are the same, and the rest of the array (i.e., the second through next-to-last elements ) form a palindrome.
My code so far:
bool isPalindrome(int arr[], int n)
{
if (n == 0 || n == 1)
{
return true;
}
else if (arr[n-1] == isPalindrome(arr[((n-1) - n) +1 ], n))
{
return true;
}
else
{
return false;
}
}
Recursion mostly has three main components:
a stopping condition (when you reach an array size small enough to be a guaranteed palindrome (0 or 1)),
a computation step (e.g. to compare the first and last item of the array and determine whether it makes sense to continue) and
a data subset selection for the nested recursion call (e.g. an array of size n - 2, excluding the first and last characters, which we already compared and found “palindrome-worthy”).
The three components in code:
bool isPalindrome(int arr[], size_t n) {
return n < 2 || (
arr[0] == arr[n - 1] &&
isPalindrome(arr + 1, n - 2));
}
Of course you may want to test the function a bit (and do not forget to run it under valgrind as well):
#include <iostream>
int main() {
std::cout << isPalindrome((int[0]){}, 0) << std::endl;
std::cout << isPalindrome((int[1]){1}, 1) << std::endl;
std::cout << isPalindrome((int[2]){1, 1}, 2) << std::endl;
std::cout << isPalindrome((int[2]){2, 1}, 2) << std::endl;
std::cout << isPalindrome((int[2]){1, 2}, 2) << std::endl;
std::cout << isPalindrome((int[3]){1, 2, 1}, 3) << std::endl;
std::cout << isPalindrome((int[3]){2, 2, 2}, 3) << std::endl;
std::cout << isPalindrome((int[3]){2, 2, 1}, 3) << std::endl;
std::cout << isPalindrome((int[4]){1, 2, 1, 2}, 4) << std::endl;
std::cout << isPalindrome((int[4]){1, 2, 2, 1}, 4) << std::endl;
std::cout << isPalindrome((int[4]){1, 2, 3, 2}, 4) << std::endl;
std::cout << isPalindrome((int[4]){2, 3, 2, 1}, 4) << std::endl;
std::cout << isPalindrome((int[4]){1, 3, 3, 1}, 4) << std::endl;
}
As a side note, this^^^ deadly struggle with arrays suggests that a different data type would be a much better choice. For example, std::string or std::vector can be initialized way easier, should be passed by reference and, as a bonus, STL containers carry size information with them. Additionally, you can use std::string_view for substrings and std::span for “subvectors” in your recursion, without copying the container over and over on each recursion level.
Here’s an example with std::string_view and three different implementations (one with recursion and two without recursion):
#include <iostream>
#include <string_view>
bool isPalindrome1(const std::string_view s) {
return s.size() < 2 || (
s[0] == s[s.size() - 1] &&
isPalindrome1(s.substr(1, s.size() - 2)));
}
bool isPalindrome2(const std::string_view s) {
const size_t end = s.size() / 2;
for (size_t i = 0; i < end; ++i)
if (s[i] != s[s.size() - i - 1])
return false;
return true;
}
bool isPalindrome3(const std::string_view s) {
auto b = s.begin();
const auto end = b + s.size() / 2;
auto e = s.rbegin();
for (; b < end; ++b, ++e)
if (*b != *e) return false;
return true;
}
int main() {
for (auto isPalindrome : {isPalindrome1,
isPalindrome2,
isPalindrome3}) {
std::cout << isPalindrome("") << std::endl;
std::cout << isPalindrome("a") << std::endl;
std::cout << isPalindrome("ab") << std::endl;
std::cout << isPalindrome("aa") << std::endl;
std::cout << isPalindrome("abc") << std::endl;
std::cout << isPalindrome("aba") << std::endl;
std::cout << isPalindrome("baab") << std::endl;
std::cout << isPalindrome("baba") << std::endl;
}
}
isPalindrome does not accept an int as a first argument. It accepts only an array, by doing this: arr[((n-1) - n) +1] you are feeeding it an int instead if an array of ints. This ((n-1) - n) +1 will evaluate to a “position” in the array, eg: arr[0] being the first element, your case an int.
Related
there is code.
#include "pch.h"
#include <algorithm>
#include <iostream>
#include <vector>
#include <stdlib.h>
using namespace std;
vector<int> SearchInt(vector<int> vec, int num) {
vector<int> temp(2);
sort(begin(vec), end(vec));
int j = 0;
for (int i : vec) {
if (i > num) {
temp[0] = i;
temp[1] = j;
return { temp };
}
//cout << i << " !>= " << num << endl ;
j++;
}
cout << "NO";
exit(0);
}
int main()
{
int n;
cin >> n;
vector<int> nums(n, 0);
vector<int> NewNums(n, 0);
for (int i = 0; i < n; i++) {
cin >> nums[i];
}
if (n != nums.size()) {
cout << "://";
return 0;
}
sort(begin(nums), end(nums));
NewNums[1] = nums[nums.size() - 1];
nums.erase(nums.begin() + nums.size() - 1);
NewNums[0] = nums[nums.size() - 1];
nums.erase(nums.begin() + nums.size() - 1);
for (int j = 2; j <= NewNums.size() - 1; j++) {
NewNums[j] = SearchInt(nums, NewNums[j-1]- NewNums[j-2])[0];
nums.erase(nums.begin() + SearchInt(nums, NewNums[j] - NewNums[j - 1])[1]);
}
if (NewNums[NewNums.size()-1] < NewNums[NewNums.size() - 2] + NewNums[0]) {
cout << "YES" << endl;
for (int i : NewNums) {
cout << i << " ";
}
return 0;
}
else {
cout << "NO";
return 0;
}
}
His task is to check whether it is possible from the given Each number is less than the sum of the two adjacent ones.
(each number is less than both of two adjacent ones)
But there is a problem - with a large number of numbers, the code takes too long. Please help me to optimize it, or just give some advice.
numbers cаn not be null.
time limit: 3.0 s
n <= 500000
You are given n numbers a1, a2,…, an. Is it possible to arrange them in a circle so that each number is strictly less than the sum of its neighbors?
For example, for the array [1,4,5,6,7,8], the left array satisfies the condition, while the right array does not, since 5≥4 + 1 and 8> 1 + 6.
Input data
The first line contains one integer n (3≤n≤105) - the number of numbers.
The second line contains n integers a1, a2,…, an (1≤ai≤109) - the numbers themselves. The given numbers are not necessarily different.
Output
If there is no solution, print "NO" on the first line.
If it exists, print "YES" on the first line. After that, on the second line print n numbers - the elements of the array in the order in which they will stand on the circle. The first and last elements you print are considered neighbors on the circle. If there are multiple solutions, output any of them. You can print a circle starting with any of the numbers.
First I'll only briefly analyze technical shortcomings of your code - without analyzing its meaning. After that I'll write my solution of the problem you defined.
Performance problems of your code are due to some strange decisions:
(1) passing std::vector<int> by value and not by reference to SearchInt function - this implies allocating and copying of the whole array on each function invocation,
(2) call SearchInt two times per loop iteration in function main instead of only one,
(3) sort array within each invocation of SearchInt - it is already sorted before the loop.
To be honest your code feels ridiculously time-consuming. I'm only wondering if that was your intention to make it as slow as you possibly can...
I will not analyze correctness of your code according to problem description. To be honest even after fixing technical shortcomings your code seems to me utterly sub-optimal and quite incomprehensible - so it is just easier to solve the problem from scratch to me.
The answer to the problem as defined is YES if the biggest number is smaller than the sum of the second big and the third big and NO otherwise - this follows from the fact that all numbers are positive (in range 1 - 109 according to newly found problem description). If the answer is YES then to make a circle that satisfies the problem description you just need in a sorted sequence of input numbers switch places of the biggest number and the next big one - that's all.
Here is my code for that (for slightly relaxed input format - I'm not checking if number of items is on a separate line and that all items are on the same line - but all correct inputs will be parsed just fine):
#include <set>
#include <iostream>
int main()
{
std::multiset<unsigned> input_set;
unsigned n;
if( !( std::cin >> n ) )
{
std::cerr << "Input error - failed to read number of items." << std::endl;
return 2;
}
if( n - 3U > 105U - 3U )
{
std::cerr << "Wrong number of items value - " << n << " (must be 3 to 105)" << std::endl;
return 2;
}
for( unsigned j = 0; j < n; ++j )
{
unsigned x;
if( !( std::cin >> x ) )
{
std::cerr << "Input error - failed to read item #" << j << std::endl;
return 2;
}
if( x - 1U > 109U - 1U )
{
std::cerr << "Wrong item #" << j << " value - " << x << " (must be 1 to 109)" << std::endl;
return 2;
}
input_set.insert(x);
}
std::multiset<unsigned>::const_reverse_iterator it = input_set.rbegin();
std::multiset<unsigned>::const_reverse_iterator it0 = it;
std::multiset<unsigned>::const_reverse_iterator it1 = ++it;
if( *it0 >= *it1 + *++it )
{
std::cout << "NO (the biggest number is bigger than the sum of the second big and the third big numbers)" << std::endl;
return 1;
}
std::cout << "YES" << std::endl;
std::cout << "Circle: " << *it1 << ' ' << *it0;
do
{
std::cout << ' ' << *it;
}
while( ++it != input_set.rend() );
std::cout << std::endl;
return 0;
}
I am following along the great book C++17 by Example, which introduces C++17 by showcasing a series of mini projects -- very cool.
However, in chapter 2, where a Set is implemented on top of a LinkedList, there is this code:
void Set::read(std::istream& inStream) {
int size;
inStream >> size;
int count = 0;
while (count < size) {
double value;
inStream >> value;
insert(value);
++count;
}
}
void Set::write(std::ostream& outStream) {
outStream << "{";
bool firstValue = true;
Iterator iterator = first();
while (iterator.hasNext()) {
outStream << (firstValue ? "" : ", ") << iterator.getValue();
firstValue = false;
iterator.next();
}
outStream << "}";
}
int main() {
Set s, t;
s.read(std::cin);
t.read(std::cin);
std::cout << std::endl << "s = ";
s.write(std::cout);
std::cout << std::endl;
std::cout << std::endl << "t = ";
t.write(std::cout);
std::cout << std::endl << std::endl;
// snip
}
I am fairly new to C++, and I do not know how to run this. Of course, I did some research before asking, but the way I came up with does not produce the expected results:
lambdarookies-MacBook:02-the-set-class lambdarookie$ ./02-the-set-class
1 2 3
3 4 5
s = {2} // Expected: s = {1, 2, 3}
t = {3, 4, 5}
Now I am wondering:
Is this simply not the right way to supply arguments, or
it is the right way, and the bug must be elsewhere in the code?
The first number Set::read reads is the size of the set. Then it reads that many numbers, and adds them to the set. The rest of the line is ignored by the current invocation of read, and is picked up by the next one, which is, by coincidence, the size of the next set you are testing with. Therefore, inputting 1 2 3 results in a set of size 1, with the only elem 2.
Please note: hasNext is a java-ism, unlike how the usual C++ iterators work. Perhaps you could consider also taking a look at a different manual.
I have to construct an ordered container (which must be iterable) with the following rule:
If the condition is true, the container is {1,0}, else it's {0,1}
I have the following code, but I don't find it "elegant":
vector<int> orderedSides;
if (condition)
{
orderedSides.push_back(1);
orderedSides.push_back(0);
}
else
{
orderedSides.push_back(0);
orderedSides.push_back(1);
}
Is there a better way to do this (from concision and performance point of view)?
You might implement something like this:
vector<int> orderedSides(2, 0);
(condition ? orderedSides.front() : orderedSides.back()) = 1;
which is a little bit shorter than explicit if clauses.
As #Deduplicator mentioned below, we might rewrite the second line in a more concise way:
orderedSides[!condition] = 1;
vector<int> orderedSides;
orderedSides.push_back(condition ? 1 : 0);
orderedSides.push_back(condition ? 0 : 1);
I don't think it's more performant but I find it more elegant.
You could compromise between efficiency and avoiding repetition, initialise the first with the condition and the second from the first.
vector<int> orderedSides(1, bool(condition)) ;
orderedSides.push_back(!orderedSides.back());
orderedSides.push_back(0);
orderedSides.push_back(1);
if (condition)
std::iter_swap(orderedSides.begin(), orderedSides.begin()+1);
I know this take bits cost. As one of candidates.
If building the elements (the ints in your question, whatever it is in real life) is free and side-effect-less:
static const int data[] = { 0, 1, 0 };
std::vector<int> orderedSides (data+condition, data+condition+2);
Full program example:
#include <iostream>
#include <vector>
std::vector<int> make(bool cond)
{
static const int data[] = { 0, 1, 0 };
return std::vector<int> (data+cond, data+cond+2);
}
std::ostream& operator<<(std::ostream& os, const std::vector<int>& v)
{
return os << "{ " << v[0] << ", " << v[1] << " }";
}
int main()
{
std::cout << "true: " << make(true) << "\n"
<< "false: " << make(false) << "\n";
}
Prints:
true: { 1, 0 }
false: { 0, 1 }
Demo
You can populate a std::vector from an array, even in C++98.
Here's an example:
#include <iostream>
#include <vector>
int main() {
bool condition = false;
std::cout << "condition is: " << std::boolalpha << condition << '\n';
int arr[][2] = {{0,1}, {1,0}};
int index = condition;
std::vector<int> v(arr[index], arr[index]+2);
for (int i = 0; i < v.size(); i++)
std::cout << v[i] << ' ';
std::cout << '\n';
}
The output is:
$ g++ tt.cc && ./a.out
condition is: false
0 1
For reference:
http://en.cppreference.com/w/cpp/container/vector/vector
I want to find Palindrome of a word. Whats Wrong Here?
main function:
int size;
string input;
cin>>input;
size = input.length();
if(testPalindrome(input,size-1,0))
cout<<"It's Palindrome";
else
cout<<"It's not Palindrome";
And the testPalindrome function is:
bool testPalindrome (string pal , int last, int first){
if (pal[first] != pal[last])
return false;
else{
if (first<last)
testPalindrome(pal,last-1,first+1);
else
return true;
}
}
I have read this link and found the answer for determining Palindromes, but why this one is not working?
You need to return the result of the recursive call, just like when you call any other function.
If you don't, the behaviour is undefined.
I think you forgot the return statement in the function
if (first<last)
return testPalindrome(pal,last-1,first+1);
^^^^^^^
Usually the first parameter of a range specifies the lower value and the second parameter specifies either the upper value of the range that is not included in the range or the number of elements in the sequence..
And the first parameter should be declared as having constant reference type because the string itself is not changed and you will escape additional memory allocation.
The recursive function can be written like
#include <iostream>
#include <string>
bool testPalindrome(const std::string &s,
std::string::size_type i,
std::string::size_type n)
{
return n < 2 || (s[i] == s[n-1] && testPalindrome(s, i + 1, n - 2) );
}
int main()
{
std::cout << testPalindrome("abba", 0, 4) << std::endl;
std::cout << testPalindrome("aba", 0, 3) << std::endl;
std::cout << testPalindrome("aa", 0, 2) << std::endl;
std::cout << testPalindrome("a", 0, 1) << std::endl;
std::cout << testPalindrome("ab", 0, 2) << std::endl;
return 0;
}
The program output is
1
1
1
1
0
The simplest way to check whether an object of the type std::string is a palindrome is to write the expression
s == std::string( s.rbegin(), s.rend() )
I'm trying to design a program that takes an integer array as input, and then returns all combinations of values that add up to a predetermined sum. For the sake of clarity, my recursive function will return true when the total adds up to 10.
However, I also want it to return the values from the array that comprise of this total, so my definition is as follows;
If suminarray returns true, print each number from the array.
My hope was, once my base clause is reached, the recursion would unwind, and my if statements would all be evaluated, and each value would be printed from my if statement. However, all that is printed is last value from the array which made up the target total, not all the values that preceded it.
I've likely misunderstood the recursive behaviour of C++. I know how to work with recursive return calls, but logically, if the if statement can't be evaluated until the recursive function returns true or false, shouldn't they unwind, also?
#include <iostream>
bool suminarray(int *numbers, const int &size, int startPos, int total);
using namespace std;
int main()
{
int numbers[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int startPos = 0;
int total = 0;
suminarray(numbers, 10, 0, total);
return 0;
}
bool suminarray(int *numbers, const int &size, int startPos, int total)
{
if(total == 10)
{
cout << "result. " << endl;
return true;
}
else if(total > 10)
{
return false;
}
else
{
for(int i = startPos; i < size; i++)
{
cout << " loop " << i << endl;
cout << " total" << total << endl;
if(suminarray(numbers, size, i+1, total+numbers[i]) == true)
{
cout << "Uses " << numbers[i] << endl;
}
}
}
}
Edit: correction to source code.
The immediate problem (which your compiler should be warning you about), is that you have no return statement in the final else block, which causes the function to fall off the end without returning either true or false, leading to undefined behavior. If you fix that in the most obvious way:
else
{
for(int i = startPos; i < size; i++)
{
cout << " loop " << i << endl;
cout << " total" << total << endl;
if(suminarray(numbers, size, i, total+numbers[i]) == true)
{
cout << "Uses " << numbers[i] << endl;
return true;
}
}
return false;
}
your program then works, but it only prints the FIRST set of values that add up to 10 that it finds.
That immediately shows you the problem with your approach -- each function call can only return ONCE -- you can't (easily) have it both return success AND continue to try more alternatives.
As you've already guessed, the way you're imagining the recursive function unwinding is wrong.
In your example, you want to get to a total of 10, with numbers starting at 1, and ending at 9. So, first your recursive function will make the total = 1. Then it will add another 1 to that until it gets all the way down to the tenth 1. Then it will print result, then it will unwind 1 step, and print 1.
Good so far right? Well, here's where it goes off track. At this point it doesn't unwind all the way. It still stays at 9, but this time it adds a 2 to that, fails goes back until it unwinds to a sum of 8. Now it tries 2 and works this time! Printing result, then 2.
This, as i've understood, isn't what you want. What you should be doing is make something else to hold your array of answers, and not just print them.
I know how to work with recursive return calls, but logically, if the if statement can't be evaluated until the recursive function returns true or false, shouldn't they unwind, also?
This is correct. The reason you are only seeing one print statement at the end is because only one call is returning 'true'. Therefore the 'if' statement is only true once and you only see one print statement for "Uses ".
I believe your mistake is that you didn't add a return statement after your for loop. This means the return value for your function is actually undefined. Start using the -Wall flag when you compile to make sure you don't make this mistake. Here is a version where I added a "return true;" after the 'for' loop:
#include <iostream>
bool suminarray(int *numbers, const int &size, int startPos, int total);
using namespace std;
int main()
{
int numbers[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int startPos = 0;
int total = 0;
suminarray(numbers, 10, startPos, total);
return 0;
}
bool suminarray(int *numbers, const int &size, int startPos, int total)
{
if(total == 10)
{
cout << "result. " << endl;
return true;
}
else if(total > 10)
{
return false;
}
else
{
for(int i = startPos; i < size; i++)
{
cout << " loop " << i << endl;
cout << " total" << total << endl;
if(suminarray(numbers, size, i, total+numbers[i]) == true)
{
cout << "Uses " << numbers[i] << endl;
}
}
}
return true;
}