I'm trying to read a textfile that I've edited with Vim into an array.
The textfile is 30*50 and is composed of single digit numbers. I've been going crazy trying to get it to work, but I think I'm having issues due to newline characters. Here's what I've been using:
Map::Map(char* filename)
{
grid[30][50] = (0);
string line;
ifstream m_file(filename);
if (m_file.is_open())
{
while(m_file.good())
{
for (int i = 0; i < 30; i++)
{
getline(m_file,line);
for (int k = 0; k < 50; k++)
{
int tnum = atoi(line.c_str());
grid[i][k] = tnum;
}
}
}
m_file.close();
}
};
grid is defined in the header file as int grid[30][50].
The code I use to print is as follows:
void display_room(int trid[30][50])
{
for (int i = 0; i < 30; i++)
{
for (int k = 0; k < 50; k++)
{
mvprintw(i,k,"%d",trid[i][k]);
};
};
};
after calling Map sMap = Map("testmap");
I'm simply trying to capture the single digit numbers into an array, and reprint that array (using curses). Currently, it reads the testmap file, and prints all zeros, no matter what is in the testmap file.
If I understand Your problem: Your parsing sets the value from the entire line where only a digit should be...
int tnum = atoi(line.c_str());
grid[i][k] = tnum;
Translating the digit (ASCII to an int/byte/... can be done in this way:
grid[i][k] = line[k] - '0';
(Perhaps some casting is needed.)
In the inner loop, you're calling atoi with the full content of the line each time. As the line is 50 character long, atoi cannot convert it to an int (the largest representable value by an int is 2147483647, and your number is probably larger than that). When atoi fails, it return 0.
What you want is convert each character of the line into an int. Something like that:
for (int i = 0; i < 30; i++)
{
getline(m_file,line);
for (int k = 0; k < 50; k++)
{
// The ASCII character of the digits 0 to 9 have
// successives values.
int tnum = line[k] - '0';
grid[i][k] = tnum;
}
}
Look at your code again. Try to see what is actually says instead of what you hope it says
int tnum = atoi(line.c_str());
You clear want that line to read each of the fifty numbers on the line in turn. But it doesn't say that. It tries to turn the whole line into an integer (and tries to do that fifty times).
Since your numbers are single digits, you actually need something much simpler
int tnum = line[k] - '0';
By saying line[k] you will get a different digit each time round the loop (because k increases each time round the loop). The - '0' bit is just a trick to turn a character into an integer. See if you can work out how it works.
Related
The problem is simple. I'm given N - the number of digits in a number and then N digits of a number. I need to do exactly one digit-switch and get the highest number possible. I did do the problem right (as in gives out the right number) but it will be hitting the 1 second time restriction afaik. How do I improve on the efficiency of my program so it would go under the 1 second time restriction with N <= 10^6. New on Stack overflow so tell me if I did something wrong
with asking the question so I can fix it. Thanks. Here's my solution:
main:
int n;
cin >> n;
int a[n+1];
for(int i=0;i<n;++i)
cin >> a[i];
int maxofarray1;
bool changeHappened=false;
bool thereAreTwoSame=false;
for(int i=0;i<n;++i) //changing the two digits to make the highest number if possible
{
maxofarray1=maxofarray(a,i+1,n);
if(a[i]<maxofarray1)
{
int temp=a[a[n]];
a[a[n]]=a[i];
a[i]=temp;
changeHappened = true;
break;
}
}
for(int i=0;i<n;++i) //need to check if there are two of the same digit so I can change
//those two making the number the same instead of making it lower
for(int j=i+1;j<n;++j)
if(a[i]==a[j])
{
thereAreTwoSame=true;
break;
}
if(!changeHappened) //if the change has not been yet made, either leaving the number as is
//(changing two same numbers) or changing the last two to do as little "damage" to the number
{
if(!thereAreTwoSame)
{
int temp=a[n-1];
a[n-1]=a[n-2];
a[n-2]=temp;
}
}
for(int i=0;i<n;++i)
cout << a[i] << " ";
return 0;
maxofarray:
int maxofarray(int a[], int i,int n) //finding the maximum of the array from i to n
{
int max1=0;
int maxind;
for(int j=i;j<n;++j)
{
if(max1<a[j])
{
max1=a[j];
maxind=j;
}
}
a[n]=maxind; //can't return both the index and maximum (without complicating with structs)
//so I add it as the last element
return max1;
}
The problem in your code is complexity. I didn't fully understand your algorithm, but having nested loops is a red flag. Instead of trying to improve bits and pieces of your code you should rather rethink your overall strategy.
Lets start by assuming the digit 9 does appear in the number. Consider the number is
9...9 c ...9...
where 9...9 are the leading digits that are all 9 (possibly there are none of them). We cannot make the number bigger by swapping one of those.
c is the first digits !=9, ie its the place where we can put a 9 to get a bigger number. 9 is the digit that will make the number maximum when put in this place.
Last, ...9... denotes the last appearance of the digit 9 and digits sourrinding that. After that 9 no other 9 appears. While we increase the number by replacing c, the number will get smaller be replacing that 9, hence we have to choose the very last one.
For the general case only a tiny step more is needed. Here is a rough sketch:
std::array<size_t,10> first_non_appearance;
std::array<size_t,10> last_appearance;
size_t n;
std::cin >> n;
std::vector<int> number(n);
for (size_t i=0;i <n;++i) {
std::cin >> a[i];
for (int d=0;d<10;++d) {
// keep track of first and last appearance of each digit
}
}
size_t first = 0;
size_t second = 0;
for (int d=0;d<10;++d) {
// determine biggest digit that appeared and use that
}
std:swap( a[first],a[last] );
It is not complete, perhaps requires handling of special cases (eg number with only one digit), but I hope it helps.
PS: You are using a variable length array (int a[n+1];), this is not standard C++. In C++ you should rather use a std::vector when you know the size only at runtime (and a std::array when the size is known).
VLA (variable length arrays) are not standard. So instead of using this nonstandard feature, you might want to use a STL data type.
Given N is rather big, you also avoid stack overflow, given that VLA are allocated on the stack. And STL containers with variable length allocate on the heap.
Then, as you pointed out yourself, it makes sense to remember the index of the last occurrence of each digit, avoiding to search over and over again for a swap candidate index.
Your implementation idea is basically, to replace the first digit from the left, which has a bigger replacement to the right of it.
This is how I did it:
static void BigSwap(std::string& digits)
{
int64_t fromRight[10];
size_t ndigitsFound = 0;
for (size_t i = 0; i < 10; i++)
fromRight[i] = -1;
size_t i = digits.size() - 1;
while (ndigitsFound < 10 && i > 0)
{
if (-1 == fromRight[digits[i] - '0'])
{
fromRight[digits[i] - '0'] = static_cast<int64_t>(i);
ndigitsFound++;
}
i--;
}
for (size_t j = 0; j < digits.size(); j++)
{
char d = digits[j] - '0';
for (char k = 9; k > d; k--)
{
if (fromRight[k] != -1 && static_cast<size_t>(fromRight[k]) > j)
{
auto temp = digits[j];
digits[j] = k + '0';
digits[fromRight[k]] = temp;
return;
}
}
}
}
class Solution {
public:
string reverseWords(string s) {
int previousWhiteSpace = 0;
for(int i = 0; i <= s.size(); i ++){
if(isspace(s[i]) || i == s.size()){
for(int j = previousWhiteSpace; j < i/2; j++){
char temp = s[j];
s[j] = s[i-1-j];
s[i-1-j] = temp;
}
previousWhiteSpace = i + 1;
}
}
return s;
}
};
Hi. So the goal of my function is to reverse the input of a string. So for example, if I am given "Let's take LeetCode contest" , my function should return "s'teL ekat edoCteeL tsetnoc" . However, currently my function is ONLY returning
"s'teL take LeetCode contest" . I have a counter which I indicate as previousWhiteSpace to keep track of the start of every new word that seems to work for the first word, but not the rest. Any help would be appreciated.
You can simply assign " " to the variable previousWhiteSpace and no need to increment. thus your code will detect white space automatically till the end of the string and will run the code after every white space. As you have assigned value 0 to it will only perform the result for the first word and it will terminate.
New to C++ and So here is part of a project I'm working on, taking a string and printing the most commonly used number along with how many times it was used. i thought this was right, but for some reason my char array wont be read in. any tips or suggestions on how to fix?
#include <string>
#include <iostream>
using namespace std;
char getMostFreqLetter(string ss);
int main() {
string s; //initilizing a variable for string s
s = ("What is the most common letter in this string "); // giving s a string
getMostFreqLetter(s); // caling the function to print out the most freq Letter
return 0;
}
char getMostFreqLetter(string ss) {
int max, index, i = 0;
int array[255] = {0};
char letters[];
// convert all letters to lowercase to make counting letters non case sensative
for (int i = 0; i < ss.length(); i ++){
ss[i] = tolower(ss[i]);
}
//read each letter into
for (int i = 0; i < ss.length(); i ++){
++array[letters[i]];
}
//
max = array[0];
index = 0;
for (int i = 0; i < ss.length(); i ++){
if( array[i] > max)
{
max = array[i];
index = i;
}
}
return 0;
}
If you are not considering white space as letter.
Then more efficient way could have been
vector<int> count(26,0);
for (int i = 0; i < s.length(); i++) {
int range = to_lower(s[i])-'a';
if ( range >= 0 && range < 26)
count[range]++;
}
// Now you can do fix the max while iterating over count;
Use string::c_str().
It converts a string to a character array.
You have a few errors in your code.
Firstly, the array of chars letters is completely unused. You should disregard it and iterate over the string ss instead which is what I think you intended to do.
This would change your second for loop from ++array[letters[i]]; to ++array[ss[i]];.
Secondly, your last for loop is buggy. You are using i as the index to look for the frequency in array whereas you need to use the ascii value of the character (ss[i]) instead. Here is a fixed version with comments:
index = ss[0];
max = array[index];
for (int i = 0; i < ss.length(); i ++){
if(!isspace(ss[i]) && array[ss[i]] > max)
{
max = array[ss[i]]; // you intended to use the ascii values of the characters in s to mark their place in array. In you code, you use i which is the just the index of the character in s as opposed to the ascii value of that character. Hence you need to use array[ss[i]].
index = ss[i];
}
}
return index;
Once you make the above changes you get the following output when run on your string:
Most freq character: t
I am trying to solve this problem:
Given a string array words, find the maximum value of length(word[i]) * length(word[j]) where the two words do not share common letters. You may assume that each word will contain only lower case letters. If no such two words exist, return 0.
https://leetcode.com/problems/maximum-product-of-word-lengths/
You can create a bitmap of char for each word to check if they share chars in common and then calc the max product.
I have two method almost equal but the first pass checks, while the second is too slow, can you understand why?
class Solution {
public:
int maxProduct2(vector<string>& words) {
int len = words.size();
int *num = new int[len];
// compute the bit O(n)
for (int i = 0; i < len; i ++) {
int k = 0;
for (int j = 0; j < words[i].length(); j ++) {
k = k | (1 <<(char)(words[i].at(j)));
}
num[i] = k;
}
int c = 0;
// O(n^2)
for (int i = 0; i < len - 1; i ++) {
for (int j = i + 1; j < len; j ++) {
if ((num[i] & num[j]) == 0) { // if no common letters
int x = words[i].length() * words[j].length();
if (x > c) {
c = x;
}
}
}
}
delete []num;
return c;
}
int maxProduct(vector<string>& words) {
vector<int> bitmap(words.size());
for(int i=0;i<words.size();++i) {
int k = 0;
for(int j=0;j<words[i].length();++j) {
k |= 1 << (char)(words[i][j]);
}
bitmap[i] = k;
}
int maxProd = 0;
for(int i=0;i<words.size()-1;++i) {
for(int j=i+1;j<words.size();++j) {
if ( !(bitmap[i] & bitmap[j])) {
int x = words[i].length() * words[j].length();
if ( x > maxProd )
maxProd = x;
}
}
}
return maxProd;
}
};
Why the second function (maxProduct) is too slow for leetcode?
Solution
The second method does repetitive call to words.size(). If you save that in a var than it working fine
Since my comment turned out to be correct I'll turn my comment into an answer and try to explain what I think is happening.
I wrote some simple code to benchmark on my own machine with two solutions of two loops each. The only difference is the call to words.size() is inside the loop versus outside the loop. The first solution is approximately 13.87 seconds versus 16.65 seconds for the second solution. This isn't huge, but it's about 20% slower.
Even though vector.size() is a constant time operation that doesn't mean it's as fast as just checking against a variable that's already in a register. Constant time can still have large variances. When inside nested loops that adds up.
The other thing that could be happening (someone much smarter than me will probably chime in and let us know) is that you're hurting your CPU optimizations like branching and pipelining. Every time it gets to the end of the the loop it has to stop, wait for the call to size() to return, and then check the loop variable against that return value. If the cpu can look ahead and guess that j is still going to be less than len because it hasn't seen len change (len isn't even inside the loop!) it can make a good branch prediction each time and not have to wait.
I'm new to C++ and I'm trying to do something that should be pretty basic.
I have a small loop in C++ that just displays a sequence of numbers and I would like to convert these numbers into specific ASCII characters. Something like this:
for (int k = 0; k < 16; k++) {
display(65+k);
}
And the result should look like this:
ABCDEFGH... etc
Any ideas?
Thanks!
EDIT based on clarification:
Judging from the error message display takes a C-style string. You can build one like this:
for (int k = 0; k < 16; k++) {
char str[2] = { 65 + k }; // Implicitly add the terminating null.
display(str);
}
That would be
#include <iostream>
int main() {
for (int k = 0; k < 16; k++) {
std::cout.put(65+k);
}
}
for C++