Beginners sincerely ask for advice about string - string

What the class describes is about "reversing a string", which is correct and usable from the Leetcode website. Today, I want to present "reversing a string" by inputting a value by myself (such as the int main() part below), but I still can't execute it after thinking for a long time. Beginners sincerely ask for advice, maybe you can also attach your writing so that I can learn, thank you.
#include <iostream>
#include <string>
using namespace std;
class Solution
{
public:
string reverseWords(string s)
{
if (s.size() == 0)
{
return s;
}
int front = 0, back = 0;
for (int i = 0; i < s.size() - 1; i++)
{
if (s[i] != ' ')
{
back++;
}
else
{
reverse(s.begin() + front, s.begin() + back);
front = back + 1;
back = front;
}
}
back++;
reverse(s.begin() + front, s.begin() + back);
return s;
}
};
int main()
{
Solution word01;
string s1= "Hello caterpillar";
word01 s1;
cout << s1.reverseWords();
}

Your code is pretty good, however we just want to reverse the words not the chars, for that we can use a while loop.
Similarly using two pointers, this'd pass just fine:
// The following block might trivially improve the exec time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
std::cout.tie(NULL);
return 0;
}();
// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <string>
#include <algorithm>
static const struct Solution {
using ValueType = std::uint_fast16_t;
std::string reverseWords(std::string s) {
std::reverse(std::begin(s), std::end(s));
ValueType len = std::size(s);
ValueType index = 0;
for (auto left = 0; left < len; ++left) {
if (s[left] != ' ') {
if (index) {
s[index++] = ' ';
}
ValueType right = left;
while (right < len && s[right] != ' ') {
s[index++] = s[right++];
}
std::reverse(std::begin(s) + index - (right - left), std::begin(s) + index);
left = right;
}
}
s.erase(std::begin(s) + index, std::end(s));
return s;
}
};
Here is LeetCode's solution with comments:
class Solution {
public:
string reverseWords(string s) {
// reverse the whole string
reverse(s.begin(), s.end());
int n = s.size();
int idx = 0;
for (int start = 0; start < n; ++start) {
if (s[start] != ' ') {
// go to the beginning of the word
if (idx != 0) s[idx++] = ' ';
// go to the end of the word
int end = start;
while (end < n && s[end] != ' ') s[idx++] = s[end++];
// reverse the word
reverse(s.begin() + idx - (end - start), s.begin() + idx);
// move to the next word
start = end;
}
}
s.erase(s.begin() + idx, s.end());
return s;
}
};
References
For additional details, please see the Discussion Board where you can find plenty of well-explained accepted solutions with a variety of languages including low-complexity algorithms and asymptotic runtime/memory analysis1, 2.

Related

Why is my integer variable being added to my other integer variable?

I am writing a program that counts the amount of letters and words in a string given by the user. For some reason, the number of words is being added to the number of letters. If there is 3 words in the sentence and 12 letters, then it says that there is 15 words. My code is below:
#include <cs50.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
int storeLetters[] = {};
int storeWords[] = {};
// declare functions
int count_letters(string text);
int count_words(string text);
int main(void)
{
// ask user for text passage
string text = get_string("Text: ");
int numOfLetters = count_letters(text);
printf("%d",numOfLetters);
printf(" letters\n");
int numOfWords = count_words(text);
printf("%d",numOfWords);
printf(" words\n");
}
int count_letters(string text)
{
int amountOfLetters = 0;
for (int i = 0, n = strlen(text); i < n; i++)
{
if (isalpha(text[i]))
{
storeLetters[i] += 1;
amountOfLetters += storeLetters[i];
}
else
{
storeLetters[i] += 0;
amountOfLetters += storeLetters[i];
}
}
return amountOfLetters;
}
int count_words(string text)
{
int amountOfWords = 0;
for (int x = 0, n = strlen(text); x < n; x++)
{
if (text[x] == '?' || text[x] == '!' || text[x] == '.' || text[x] == ' ')
{
storeWords[x] += 1;
amountOfWords += storeWords[x];
}
else
{
storeWords[x] += 0;
amountOfWords += storeWords[x];
}
}
return amountOfWords;
}
storeLetters and storeWords are arrays, which you initialize to zero length. If you access storeLetters[0] (or any other index), you go past the end. It's not gonna work.
You don't need those variables at all. Just increment amountOfLetters directly.
int count_letters(string text)
{
int amountOfLetters = 0;
for (int i = 0, n = strlen(text); i < n; i++)
{
if (isalpha(text[i]))
{
amountOfLetters += 1;
}
}
return amountOfLetters;
}

CS50 speller pset 5 (accessed 1 byte that does not belong to me but can't find the byte)

After running my code through help50 Valgrind, I got the following error message:
==6830== Invalid read of size 1
==6830== at 0x4C33614: strcasecmp (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6830== by 0x401176: check (dictionary.c:52)
==6830== by 0x400CD9: main (speller.c:112)
Looks like you're trying to access 1 byte of memory that isn't yours? Did you try to index into an array beyond its bounds? Take a closer look at line 52 of dictionary.c.
I think it has something to do with my check function but line 52 is just an if statement and I can't figure out where I'm trying to access that 1 byte from.**
My code is below:
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <strings.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 1000;
//Number of words
unsigned int noWords = 0;
//Variable to check if dictionary loaded
bool isLoaded = false;
// Hash table
node *table[N];
// Returns true if word is in dictionary else false
bool check(const char *word)
{
//Changing letters to lower case because case insensitive
//Copy created because word argument is a constant. copy can be edited
int n = strlen(word) + 1;
char copy[LENGTH + 1];
for (int i = 0; i < n; i++)
{
copy[i] = tolower(word[i]);
}
// Add null terminator to end string
copy[n] = '\0';
//Hash the word to convert it to index and check if it's in any of the linked lists
int index = hash(copy);
if (table[index] != NULL) //Check if word is in linked list
{
for (node *cursor = table[index]; cursor != NULL; cursor = cursor -> next)
{
if (strcasecmp(cursor -> word, copy) == 0)
{
return true;
}
}
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
//Taken from http://www.cse.yorku.ca/~oz/hash.html (by djb2)
unsigned long h = 5381;
int c;
while ((c = *word++))
{
c = tolower(c);
h = (((h << 5) + h) + c) % N; /* hash * 33 + c*/
}
return h;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
char word[LENGTH + 1];
//Open dictionary
FILE *f = fopen(dictionary, "r");
//Check if file can be opened
if (f == NULL)
{
printf("%s\n", "File cannot be opened!");
return false;
}
//Read strings from file
while (fscanf(f, "%s", word) != EOF)
{
noWords++;
node *newNodePointer = malloc(sizeof(node));
if (newNodePointer == NULL)
{
unload();
printf("Out of memory");
return false;
}
int index = hash(word);//hashtable is an array of linked list. index helps insert node into hashtable
strcpy(newNodePointer -> word, word);//Copies word from infile into new node's word field
if (table[index] == NULL)//Check if same word already exists in the bucket
{
newNodePointer -> next = NULL;
table[index] = newNodePointer;
}
else
{
newNodePointer -> next = table[index];
table[index] = newNodePointer;
}
free(newNodePointer);
}
fclose(f);
isLoaded = true;
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
if (isLoaded)
{
return noWords;
}
return 0;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
//Check if there's even a loaded dictionary
if (!isLoaded)
{
return false;
}
//Iterate through hashtable
for (int i = 0; i < N; i++)
{
if (table[i] != NULL)
{
node *cursor = table[i];
while (cursor != NULL)
{
node *tmp = table[i]; //tmp pointer continues pointing at table[i] while cursor points at next item in hashtable
cursor = cursor -> next;
free(tmp);
}
}
}
return true;
}
The problem is from here in load: free(newNodePointer);. It just released the memory where the word and the next pointer are stored!

cs50 vigenere - loops incorrectly

Apologies if the answer to this is incredibly simple. I just can't work it out.
I've been working on the CS50 Vigenere problem and I think I'm almost there. However the program loops in a way that I don't expect and I'm not sure why. Once it has printed the first ciphered character of the plaintext, it loops back to move to the next character in the key but misses out the part where it needs to move to the next character of the plain text. At least I think that is what is happening.
Here is my code. Any help would be greatly appreciated.
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv [])
{
int a;
int ciphertext;
int k;
string plain;
int cipher;
// check user has input a valid number of arguments
if (argc < 2 || argc > 2)
{
printf("please input a valid number of arguments\n");
return 1;
}
// check user has input a valid key and prompt for plaintext
char * key = argv [1];
for (a = 0; a < strlen(key); a++)
if (!isalpha(key[a]))
{
printf("Please input a valid key. Key must be alphabetical");
return 1;
}
{
if (a == strlen(key))
{
plain = get_string("Plaintext: ");
}
{
printf("ciphertext: ");
}
}
//read plaintext and keep track
{
for (int i = 0, n = strlen(plain); i < n; i++)
{
//read key and keep track
if (isalpha(plain[i]))
{
for (int j = 0, p = strlen(key); j < p; j++)
//convert key to numerical
{
if (isupper(key[j]) > 'A')
{
k = (key[j] - 65);
//calculate ciphertext and print (upper case)
{
printf("%c", (plain[i] + (k % p) %26) +65);
}
}
else if (islower(key[j]) > 'a')
{
k = (key[j] - 97);
{
printf("%c", (plain[i] + (k % p) %26) +97);
}
}
else printf("%c", plain[i]);
}
}
}
{
printf("\n");
}
}
}

Write a snippet of C/C++ code that creates this list of base-12 numbers that count from 0000 to BBBB

Im not sure what to do i want it to print 0000 to ending in BBBB i was trying to use the printf statement anyways, if anyone can help me figure this out that would be great. Thanks
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main()
{
char digits[] = "0123456789AB";
for (int column1=0; column1<=12; column1++) {
for (int column2=0; column2<=12; column2++) {
for (int column3=0; column3<=12; column3++) {
for (int column4=0; column4<=12; column4++) {
std::cout<< digits[column2]<<endl;
}
}}}
return(0);
}
The 4 for loops are not the prettiest thing ever, but they should work and I'm not sure it's worth the complications to do it differently. So keep what you have, just print all digits:
std::cout<< digits[column1]<< digits[column2] << digits[column3] << digits[column4]<<endl;
It's better to parametrize the base and the column count to avoid many nested for's.
#include <iostream>
const int columnCount = 4, base = 12;
char digitToChar(int digit) {
if(digit >= 0 && digit <= 9) {
return '0' + digit;
} else {
return 'A' + digit - 10;
}
}
bool increment(int* number) {
int currentColumn = columnCount - 1;
++number[currentColumn];
while(number[currentColumn] == base) {
number[currentColumn] = 0;
--currentColumn;
if(currentColumn < 0) {
return false;
}
++number[currentColumn];
}
return true;
}
void outputNumber(int* number) {
for(int i = 0; i < columnCount; ++i) {
std::cout << digitToChar(number[i]);
}
std::cout << std::endl;
}
int main() {
int number[columnCount] = {0, 0, 0, 0};
bool overflow = false;
do {
outputNumber(number);
overflow = !increment(number);
} while(!overflow);
return 0;
}

How to read a string value with a delimiter on Arduino?

I have to manage servos from a computer.
So I have to send manage messages from computer to Arduino. I need manage the number of servo and the corner. I'm thinking of sendin something like this : "1;130" (first servo and corner 130, delimeter ";").
Are there any better methods to accomplish this?
Here is my this code :
String foo = "";
void setup(){
Serial.begin(9600);
}
void loop(){
readSignalFromComp();
}
void readSignalFromComp() {
if (Serial.available() > 0)
foo = '';
while (Serial.available() > 0){
foo += Serial.read();
}
if (!foo.equals(""))
Serial.print(foo);
}
This doesn't work. What's the problem?
You can use Serial.readString() and Serial.readStringUntil() to parse
strings from Serial on arduino
You can also use Serial.parseInt() to read integer values from serial
Code Example
int x;
String str;
void loop()
{
if(Serial.available() > 0)
{
str = Serial.readStringUntil('\n');
x = Serial.parseInt();
}
}
The value to send over serial would be "my string\n5" and the result would be str = "my string" and x = 5
Note: Serial.available() inherits from the Stream utility class.
https://www.arduino.cc/reference/en/language/functions/communication/serial/available/
This is a Great sub I found. This was super helpful and I hope it will be to you as well.
This is the method that calls the sub.
String xval = getValue(myString, ':', 0);
This is The sub!
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = {
0, -1 };
int maxIndex = data.length()-1;
for(int i=0; i<=maxIndex && found<=index; i++){
if(data.charAt(i)==separator || i==maxIndex){
found++;
strIndex[0] = strIndex[1]+1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
Most of the other answers are either very verbose or very general, so I thought I'd give an example of how it can be done with your specific example using the Arduino libraries:
You can use the method Serial.readStringUntil to read until your delimiter from the Serial port.
And then use toInt to convert the string to an integer.
So for a full example:
void loop()
{
if (Serial.available() > 0)
{
// First read the string until the ';' in your example
// "1;130" this would read the "1" as a String
String servo_str = Serial.readStringUntil(';');
// But since we want it as an integer we parse it.
int servo = servo_str.toInt();
// We now have "130\n" left in the Serial buffer, so we read that.
// The end of line character '\n' or '\r\n' is sent over the serial
// terminal to signify the end of line, so we can read the
// remaining buffer until we find that.
String corner_str = Serial.readStringUntil('\n');
// And again parse that as an int.
int corner = corner_str.toInt();
// Do something awesome!
}
}
Of course we can simplify this a bit:
void loop()
{
if (Serial.available() > 0)
{
int servo = Serial.readStringUntil(';').toInt();
int corner = Serial.readStringUntil('\n').toInt();
// Do something awesome!
}
}
You need to build a read buffer, and calculate where your 2 fields (servo #, and corner) start and end. Then you can read them in, and convert the characters into Integers to use in the rest of your code. Something like this should work (not tested on Arduino, but standard C):
void loop()
{
int pos = 0; // position in read buffer
int servoNumber = 0; // your first field of message
int corner = 0; // second field of message
int cornerStartPos = 0; // starting offset of corner in string
char buffer[32];
// send data only when you receive data:
while (Serial.available() > 0)
{
// read the incoming byte:
char inByte = Serial.read();
// add to our read buffer
buffer[pos++] = inByte;
// check for delimiter
if (itoa(inByte) == ';')
{
cornerStartPos = pos;
buffer[pos-1] = 0;
servoNumber = atoi(buffer);
printf("Servo num: %d", servoNumber);
}
}
else
{
buffer[pos++] = 0; // delimit
corner = atoi((char*)(buffer+cornerStartPos));
printf("Corner: %d", corner);
}
}
It looks like you just need to correct
foo = ''; >>to>> foo = "";
foo += Serial.read(); >>to>> foo += char(Serial.read());
I made also shomething similar..:
void loop(){
while (myExp == "") {
myExp = myReadSerialStr();
delay(100);
}
}
String myReadSerialStr() {
String str = "";
while (Serial.available () > 0) {
str += char(Serial.read ());
}
return str;
}
This code reads string until it sees '>' character
void loop() {
// put your main code here, to run repeatedly:
String msg = getMessage();
}
String getMessage() {
String msg = "";
while (Serial.available()>0) {
msg = Serial.readStringUntil('>');
}
return msg;
}
It's universal parser
struct servo
{
int iServoID;
int iAngle;
};
std::vector<std::string> split(const std::string& str, const std::string& delim)
{
std::vector<std::string> tokens;
size_t prev = 0, pos = 0;
do
{
pos = str.find(delim, prev);
if (pos == std::string::npos) pos = str.length();
std::string token = str.substr(prev, pos-prev);
if (!token.empty()) tokens.push_back(token);
prev = pos + delim.length();
}
while (pos < str.length() && prev < str.length());
return tokens;
}
std::vector<servo> getServoValues(const std::string& message)
{
std::vector<servo> servoList;
servo servoValue;
std::vector<std::string> servoString;
std::vector<std::string> values = split(message, ",");
for (const auto& v : values)
{
servoString.clear();
servoString = split(v, ";");
servoValue.iServoID = atoi(servoString[0].c_str()); //servoString[0].toInt();
servoValue.iAngle = atoi(servoString[1].c_str());// servoString[1].toInt();
servoList.emplace_back(servoValue);
}
return servoList;
}
to call:
std::string str = "1;233,2;123";
std::vector<servo> servos = getServoValues(str);
for (const auto & a : servos)
std::cout<<a.iServoID << " " << a.iAngle << std::endl;
Result
1 233
2 123

Resources