I have to optimitze a code with a triply-recursive function. I know that these kind of functions might be really slow, specially when dealing with large numbers. I have tried to improve the following code by comparing it with an efficient code of Fibonacci, but I'm still stucked.
Could you give me some hints? How can I use a loop instead? Thanks in advance!
int f(int i) {
if (i == 0) return -3;
if (i == 1) return -1;
if (i == 2) return 4;
if (i == 3) return 8;
if (i == 4) return 15;
return f(i-5) + f(i-3) + f(i-1);
}
int main() {
int n;
while (cin >> n) {
for (int i = 0; i < n; ++i) cout << f(i) << " ";
cout << "..." << endl;
}
}
First you might store result in std::vector:
int f(int n) {
std::vector<int> res{-3, -1, 4, 8, 15};
if (n < 5) return res[n];
for (int i = 5; i != n + 1; ++i) {
res.push_back(res[i - 5] + res[i - 3] + res[i - 1]);
}
return res[n];
}
Then to reduce memory foot print, you might use only last values of the array:
int f(int n) {
int res[5] = {-3, -1, 4, 8, 15};
if (n < 5) return res[n];
for (int i = 5; i != n + 1; ++i) {
const int fi = res[0] + res[2] + res[4];
std::copy(res + 1, res + 5, res);
res[4] = fi;
}
return res[4];
}
You might even avoid the copy with circular buffer and use of modulo.
int f(int n) {
int res[5] = {-3, -1, 4, 8, 15};
if (n < 5) return res[n];
for (int i = 5; i != n + 1; ++i) {
const int fi = res[(i - 5) % 5] + res[(i - 3) % 5] + res[(i - 1) % 5];
res[i % 5] = fi;
}
return res[n % 5];
}
You might notice that ((i - 5) % 5) == (i % 5)
and replace the computation by
res[i % 5] += res[(i - 3) % 5] + res[(i - 1) % 5];
Related
I have a problem,how to efficiently find the frame head(such as 0xaa 0xbb 0xcc 0xdd) in much data(6MB,in a mmap memory) on arm board(a53 cpu). Direct traversal takes a long time.This is my code, i want to get help.
for (i = 0, j = len_25per, k = len_50per, m = len_75per; i < len_25per, j < len_50per, k < len_75per, m < cl1_dma->len; i++, j++, k++, m++)
{
if (cl1_dma->addr[i] == 0xe5)
{
if (cl1_dma->addr[i + 1] == 0x30)
{
if ((cl1_dma->addr[i + 4] | cl1_dma->addr[i + 5] << 8) == 0x0023)
{
if (cl1_dma->addr[i + 10] == 0x13)
{
find_head = 1;
location = i;
break;
}
}
}
}
if (cl1_dma->addr[j] == 0xe5)
{
if (cl1_dma->addr[j + 1] == 0x30)
{
if ((cl1_dma->addr[j + 4] | cl1_dma->addr[j + 5] << 8) == 0x0023)
{
if (cl1_dma->addr[j + 10] == 0x13)
{
find_head = 1;
location = j;
break;
}
}
}
}
...
}
Given 3 numeric sorted arrays:
int[] a;
int[] b;
int[] c;
It is necessary to find three numbers whose difference is minimal:
(a_i- b_j)^2 + (b_j - c_k)^2 + (a_i - c_k)^2 -> min
For examle:
int[] a = {7, 10, 12};
int[] b = {3, 4, 6, 9};
int[] c = {1, 2, 5, 8};
Result should be 7 6 8 (or 7 6 5) because (7 - 6)^2 + (6 - 5)^2 + (7 - 5)^2 = 6 = min
What is the best approach to this problem?
I`ve tried to use 3 variables and increment them depending on the minimum term, but unsuccessfully.
Here is my algorithm written in C++:
void printThreeClosest(int[] a, int[] b, int[] c) {
int64_t diff = (a[0] - b[0]) * (a[0] - b[0]) +
(b[0] - c[0]) * (b[0] - c[0]) +
(a[0] - c[0]) * (a[0] - c[0]);
int i_res = 0, j_res = 0, k_res = 0, i = 0, j = 0, k = 0;
while (i < a.size() && j < b.size() && k < c.size()) {
int first_term = (a[i] - b[j]) * (a[i] - b[j]);
int second_term = (b[j] - c[k]) * (b[j] - c[k]);
int third_term = (a[i] - c[k]) * (a[i] - c[k]);
int min_term = std::min(a[i], std::min(b[j], c[k]));
int64_t current_diff = first_term + second_term + third_term;
if (current_diff < diff) {
diff = current_diff;
i_res = i, j_res = j, k_res = k;
}
if (diff == 0) {
break;
}
if (first_term == min_term) {
++k;
} else if (second_term == min_term) {
++i;
} else {
++j;
}
}
std::cout << a[i_res] << " " << b[j_res] << " " << c[k_res] << "\n";
}
IMO, the straight-forward, but O(n^3) solution may be this:
void printThreeClosest(int[] a, int[] b, int[] c) {
int minVal = -1;
int resa, int resb, int resc;
for(int i=0; i<a.length && minVal != 0; i++) {
int x = a[i];
for(int j=0; j<b.length && minVal != 0; j++) {
int y = b[j];
for(int k=0; k<c.length && minVal != 0; k++) {
int z = c[k];
int sumOfSqr = ( ((x-y)*(x-y)) + ((y-z)*(y-z)) + ((z-x)*(z-x)) );
if (minVal < 0) {
minVal = sumOfSqr;
resa=x; resb=y; resc=z;
} else if (sumOfSqr < minVal) {
minVal = sumOfSqr;
resa=x; resb=y; resc=z;
}
}
}
};
std::cout << resa << ' ' << resb << ' ' << resc << std::endl;
}
This solution implemented in Javascript for quick testing is below:
const a = [7, 10, 12];
const b = [3, 4, 6, 9];
const c = [1, 2, 5, 8];
let minVal = -1;
let result = [];
const sumOfSquares = (x, y, z) => ( ((x-y)*(x-y)) + ((y-z)*(y-z)) + ((x-z)*(x-z)) );
for (let i=0; i < a.length && minVal !== 0; i++) {
for (let j=0; j < b.length && minVal !== 0; j++) {
for (let k=0; k < c.length && minVal !== 0; k++) {
const tempSum = sumOfSquares(a[i], b[j], c[k]);
if (minVal < 0) {
minVal = tempSum;
result = [a[i], b[j], c[k]];
} else if (tempSum < minVal) {
minVal = tempSum;
result = [a[i], b[j], c[k]];
}
}
}
}
console.log('result: ', result);
I would like to use this "Levenshtein" function to assess similarities between two strings (to check if user has committed a spelling mistake).
Since I work on null safe mode, it points out an error with the LIST constructor :
List<List<int>> d = List.generate(sa + 1, (int i) => List(sb + 1));
What can I write to replace List(sb+1)); ?
int levenshtein(String a, String b) {
a = a.toUpperCase();
b = b.toUpperCase();
int sa = a.length;
int sb = b.length;
int i, j, cost, min1, min2, min3;
int levenshtein;
// ignore: deprecated_member_use
List<List<int>> d = List.generate(sa + 1, (int i) => List(sb + 1));
if (a.length == 0) {
levenshtein = b.length;
return (levenshtein);
}
if (b.length == 0) {
levenshtein = a.length;
return (levenshtein);
}
for (i = 0; i <= sa; i++) d[i][0] = i;
for (j = 0; j <= sb; j++) d[0][j] = j;
for (i = 1; i <= a.length; i++)
for (j = 1; j <= b.length; j++) {
if (a[i - 1] == b[j - 1])
cost = 0;
else
cost = 1;
min1 = (d[i - 1][j] + 1);
min2 = (d[i][j - 1] + 1);
min3 = (d[i - 1][j - 1] + cost);
d[i][j] = min(min1, min(min2, min3));
}
levenshtein = d[a.length][b.length];
return (levenshtein);
}
You can use List.generate for the inner list as well.
List<List<int>> d = List.generate(sa + 1, (int i) => List.generate(sb + 1, (int j) => 0));
Also, if they're all going to be initialized to 0 you can just do this too:
List<List<int>> d = List.filled(sa + 1, List.filled(sb + 1, 0));
I have been working on implementing a grayscale gradient with different dithering methods, but the task calls for the gradient to be horizontal starting with black on the left.
In my attempts to rotate the image horizontally I have tried:
std::reverse(result.begin(), result.end())
I have also tried handling the vector like a 2D array:
temp = result[i][j];
result[i][j] = result[i][width - 1 - j];
result[i][width - 1 - j] = temp;
None of these methods have worked so far.
Here's the code I'm working with:
//***headers n stuff***
vector<vector<int>> gradient(int height, int width)
{
assert(height > 0 && width > 0);
int cf = height / 255;
int color = 0;
vector<vector<int>> result(width, vector<int>(height));
for (int i = 0; i < height; i += cf)
{
for (int j = 0; j < cf; j++)
{
fill(result[i + j].begin(), result[i + j].end(), color % 255);
}
color--;
}
stable_sort(result.begin(), result.end());
return result;
}
vector<vector<int>> Ordered(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
vector<vector<int>> temp(height, vector<int>(width));
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int xlocal = i%ditherSize;
int ylocal = j%ditherSize;
int requiredShade = diterLookup[xlocal + ylocal * 3]*255/9;
if (requiredShade >= result[i][j])
{
result[i][j] = 0;
}
else {
result[i][j] = 255;
}
}
}
return temp;
}
vector<vector<int>> Random(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
//vector<vector<int>> result(height, vector<int>(width));
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int requiredShade = rand() % 255;
if (requiredShade >= result[i][j]) {
result[i][j] = 0;
}
else {
result[i][j] = 255;
}
}
}
return result;
}
vector<vector<int>> Floyd_Steinberg(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int oldpixel = result[i][j];
int newpixel;
if (oldpixel<=127) {
newpixel = 0;
}
else {
newpixel = 255;
}
result[i][j] = newpixel;
int quanterror = oldpixel - newpixel;
if (j < width - 1) {
result[i][j+1] += quanterror * 7 / 16;
}
if (i < height - 1) {
if (j > 0){
result[i + 1][j - 1] += quanterror * 3 / 16;
}
result[i+1][j] += quanterror * 5 / 16;
if (j < width - 1) {
result[i + 1][j + 1] += quanterror * 1 / 16;
}
}
}
}
return result;
}
vector<vector<int>> JJN(int height, int width, vector<vector<int>> result)
{
int ditherSize = 3;
int diterLookup[] = { 8, 3, 4, 6, 1, 2, 7, 5, 9 };
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int oldpixel = result[i][j];
int newpixel;
if (oldpixel <= 127) {
newpixel = 0;
}
else {
newpixel = 255;
}
result[i][j] = newpixel;
int quanterror = oldpixel - newpixel;
if (j < width - 1) {
result[i][j + 1] += quanterror * 7 / 48;
if(j<width-2)
result[i][j + 2] += quanterror * 5 / 48;
}
if (i < height - 1) {
if (j > 0) {
if (j > 1)
result[i + 1][j - 2] += quanterror * 3 / 48;
result[i + 1][j - 1] += quanterror * 5 / 48;
}
result[i + 1][j] += quanterror * 7 / 48;
if (j < width - 1) {
result[i + 1][j + 1] += quanterror * 5 / 48;
if (j < width - 2)
result[i + 1][j + 2] += quanterror * 3 / 48;
}
}
if (i < height - 2) {
if (j > 0) {
if(j>1)
result[i + 2][j - 2] += quanterror * 1 / 48;
result[i + 2][j - 1] += quanterror * 3 / 48;
}
result[i + 2][j] += quanterror * 5 / 48;
if (j < width - 1) {
result[i + 2][j + 1] += quanterror * 3 / 48;
if (j < width - 2)
result[i + 2][j + 2] += quanterror * 1 / 48;
}
}
}
}
return result;
}
int main(int argc, char *argv[])
{
if (argc < 5) {
cout << "usage:" << endl << "prog.exe <filename> <width> <height> <dithering>"<<endl;
return 0;
}
stringstream w(argv[2]);
stringstream h(argv[3]);
stringstream d(argv[4]);
int numcols, numrows, dithering;
//***handling error cases ***
srand(time(0));
ofstream file;
file.open(argv[1]);
if (!file)
{
cout << "can't open file" << endl;
return 0;
}
file << "P5" << "\n";
file << numrows << " " << numcols << "\n";
file << 255 << "\n";
vector<vector<int>> pixmap{ gradient(numrows, numcols) };
switch (dithering) {
case 1:
pixmap = Ordered(numrows, numcols, pixmap);
break;
case 2:
pixmap = Random(numrows, numcols, pixmap);
break;
case 3:
pixmap = Floyd_Steinberg(numrows, numcols, pixmap);
break;
case 4:
pixmap = JJN(numrows, numcols, pixmap);
break;
default:
break;
}
for_each(pixmap.begin(), pixmap.end(), [&](const auto& v) {
copy(v.begin(), v.end(), ostream_iterator<char>{file, ""});
});
file.close();
}
And here is the result Using Ordered Dither
If your gray scale image is stored as a std::vector<std::vector<int>>, I have made the following code for you.It rotates the image by 90 degrees in the trigonometric direction:
#include <iostream>
#include <vector>
typedef std::vector<std::vector<int>> GrayScaleImage;
// To check is the GrayScaleImage is valid (rectangular and not empty matrix)
bool isValid(const GrayScaleImage & gsi)
{
bool valid(true);
if(!gsi.empty())
{
size_t width(gsi[0].size());
for(unsigned int i = 1; valid && (i < gsi.size()); ++i)
{
if(gsi[i].size() != width)
valid = false;
}
}
else
valid = false;
return valid;
}
// To print the GrayScaleImage in the console (for the test)
void display(const GrayScaleImage & gsi)
{
for(const std::vector<int> & line : gsi)
{
for(size_t i = 0; i < line.size(); ++i)
std::cout << line[i] << ((i < line.size()-1) ? " " : "");
std::cout << '\n';
}
std::cout << std::flush;
}
// To rotate the GrayScaleImage by 90 degrees in the trigonometric direction
bool rotate90(const GrayScaleImage & gsi, GrayScaleImage & result)
{
bool success(false);
if(isValid(gsi))
{
result = GrayScaleImage(gsi[0].size());
for(const std::vector<int> & line : gsi)
{
for(unsigned int i = 0; i < line.size(); ++i)
result[gsi[0].size()-1 - i].push_back(line[i]);
}
success = true;
}
return success;
}
// Test
int main()
{
GrayScaleImage original { {0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11} };
GrayScaleImage rotated;
rotate90(original, rotated);
std::cout << "Original:" << std::endl;
display(original);
std::cout << "\nRotated:" << std::endl;
display(rotated);
return 0;
}
The function that will interest you is rotate90().
The output of the test written in the main() function is:
Original:
0 1 2
3 4 5
6 7 8
9 10 11
Rotated:
2 5 8 11
1 4 7 10
0 3 6 9
As you can see, it worked successfully.
I hope it can help.
EDIT:
I tried with a real grayscale image generated and the rotate90() function worked well.Here is the view, before and after rotating the image (2 examples, landscape and portrait):
Example with landscape image
Example with portrait image
So now we know that the function works well.
I see that your result is not as expected (black area added, dimensions mismatching), that kind of behaviour can occur when you make mistakes with the dimensions of the matrixes.
EDIT2:
The invalid output are not due to rotate90() but to the PGM file generation. I think it is because the data are written as binaries but not the header.The following function I have written creates valid PGM files:
typedef std::vector<std::vector<uint8_t>> GrayScaleImage;
bool createPGMImage(const std::string & file_path, const GrayScaleImage & img)
{
bool success(false);
if(isValid(img))
{
std::ofstream out_s(file_path, std::ofstream::binary);
if(out_s)
{
out_s << "P5\n" << img[0].size() << ' ' << img.size() << '\n' << 255 << '\n';
for(const std::vector<uint8_t> & line : img)
{
for(uint8_t p : line)
out_s << p;
out_s << std::flush;
}
success = true;
out_s.close();
}
}
return success;
}
The isValid() function is the same I have given with rotate90().
I also replaced the int values by uint8_t (unsigned char) values to be more consistent as we are writing single bytes values (0-255).
So I got this introduction to Programming assignment, I have to write a program that find the nth member of the following sequence 1, 121, 1213121, 121312141213121.. and so on. Basically, the first member is 1, and every next one is made of [the previous member] [n] [the previous member]. N < 10. So I got this problem that I do not understand, tried searching for it in the internet but didn't get anything that can help me.
#include "stdafx.h"
#include <iostream>
using namespace std;
int size(int n, int realsize);
int main()
{
int n;
cin >> n;
if (n == 1) {
cout << "1";
return 0;
}
int helper = 0;
char c = '2';
char* look;
char* say;
say = new char[size(n, 1) + 1]();
look = new char[size(n - 1, 1) + 1]();
look[0] = '1';
while (helper < n) {
for (int i = 0; i < size(helper + 1, 1); i++) {
say[i] = look[i];
}
say[size(helper + 1, 1)] = c;
for (int i = size(helper + 1, 1) + 1; i < size(helper + 1, 1) * 2 + 1; i++) {
say[i] = look[i - (size(helper + 1, 1) + 1)];
}
for (int i = 0; i < size(helper + 1, 1) * 2 + 1; i++) {
look[i] = say[i];
}
helper += 1;
}
cout << say;
delete[] say;
delete[] look;
return 0;
}
int size(int n, int realsize)
{
if (n == 1)
return realsize;
else
return size(n - 1, realsize * 2 + 1);
}
You are overwriting the capacity of your look variable. It ends out being written with the entire contents of say, so it needs to have that same size as well.
While I don't condone the below code as good code, it has minimal adjustments from your own implementation and should give a more solid base to continue towards a working outcome. I tested it with the first couple of numbers, but that's no guarantee it is perfect.
#include <iostream>
using namespace std;
int size(int n, int realsize);
int main()
{
int n;
cin >> n;
if (n == 1)
{
cout << "1";
return 0;
}
int helper = 0;
char c = '2';
char * look;
char * say;
say = new char[size(n, 1) + 1]; // Ditch the () call, which is confusing.
look = new char[size(n, 1) + 1]; // Make the same size as "say"
look[0] = '1';
while (helper < n - 1) // You're overrunning this loop I think, so I did it to n - 1.
{
for (int i = 0; i < size(helper + 1, 1); i++)
{
say[i] = look[i];
}
say[size(helper + 1, 1)] = c + helper; // You were adding '2' every time, so this will add 2, 3, 4, etc incrementally.
for (int i = size(helper + 1, 1) + 1; i < size(helper + 1, 1) * 2 + 1; i++)
{
say[i] = look[i - (size(helper + 1, 1) + 1)];
}
for (int i = 0; i < size(helper + 1, 1) * 2 + 1; i++)
{
look[i] = say[i];
}
helper += 1;
}
say[size(n, 1)] = '\0'; // Null-terminate "say" before printing it out.
cout << say;
delete[] say;
delete[] look;
return 0;
}
int size(int n, int realsize)
{
if (n == 1)
return realsize;
else
return size(n - 1, realsize * 2 + 1);
}