Substring comparision with one mismatch - c++

The following is code for comparing a String A and String B with atmost one mismatch
i.e.,
ABC is same as ABX or AXC or XBC but, not same as AXZ
I did check several cases but, the website says it provides wrong answer. Could someone help to figure out where does this code fail?
Also, I'd be glad if someone could provide a better algorithm for the same problem.
TY
int compare(string a, int pos, string b) {
int count = 0;
int length = b.length()-1;
int mid = b.length() /2;
if(pos+length >= a.length())
return 0;
for(int i=0,j=pos;i<=mid;i++,j++) {
if(i == mid) {
if(a[j] != b[i])
count ++;
}
else {
if(a[j] != b[i])
count ++;
if(a[pos+length - i] != b[length -i])
count ++;
}
if(count >= 2) return 0;
}
return 1;
}

One problem is that if b.length() is even, then you compare a[pos + b.length() / 2] to b[b.length() / 2] twice: once when i == mid - 1, and once when i == mid. So something like compare("abcd", 0, "abbd") returns 0, because it counts the 'c'-vs.-'b' discrepancy as two separate mismatches.
I recommend that you simply strip out all logic related to mid. It serves no purpose other than massively complicating your code. If you iterate straight from 0 to b.length() - 1, you'll be much better off.

Related

Alphabetically partitioning indexes of substrings in C++ issues

for a while now I've been trying to get this code to work to partition (as if preparing for quicksort) the indexes of substring suffixes, and while it's close I'm not getting what I'm expecting. I was wondering if a fresh set of eyes may help.
int partition(const string &S, vector<int> &indices, int low, int high, int pivotIndex)
{
int i = low;
int j = high - 1;
swap(indices[high], indices[pivotIndex]);
while (i <= j)
{
while (i < high && !lessThan(S, S[i], S[indices[high]]))
i++;
while (j >= low && lessThan(S, S[j], S[indices[high]]))
j--;
if (i < j)
{
int temp = indices[i];
indices[i] = indices[j];
indices[j] = temp;
i++;
j--;
}
}
swap(indices[high], indices[i]);
return i;
}
Indices is simply a vector of 0, 1, 2, ..., n of same size as string S.
And here's the program I wrote for lessThan just so you know what I'm working with:
bool lessThan(const string &S, int first, int second)
{
int counter = (int)S.length() - ((first <= second) ? second : first);
for (int i = 0; i <= counter; ++i)
{
if (S[first + i] != S[second + i])
{
if (S[first + i] < S[second + i])
{
return true;
}
else
{
return false;
}
}
}
if (first < second)
{
return false;
}
else
{
return true;
}
}
lessThan seems to work just fine when I test it separately, so I don't think it's the issue, but maybe it is.
Whenever I test, with say the string "abracadabra", and setting the pivotIndex to 4, I expect to get "0 1 8 3 10 5 7 4 2 9 6" as my output but I instead get "0 1 8 3 7 5 4 10 2 9 6". Close, but not quite. Can anyone spot my mistake?
(P.S. I know I could probably use substr() or some other solution to do lessThan easier, but I'm trying to do it without allocating extra memory, my focus is on the partition function)
edit: I figured it out. Complete error on my side. Check below for answer
I was an idiot, input to lessThan was supposed to be given two ints. I instead gave it two chars from S. Also swapped which lessThan call the ! was on. I think I was just up too late programming and blame this all on sleep deprivation.
Fixed Code:
int partition(const string &S, vector<int> &indices, int low, int high, int pivotIndex)
{
int i = low;
int j = high - 1;
swap(indices[high], indices[pivotIndex]);
while (i <= j)
{ //This right here
while (i < high && lessThan(S, indices[i], indices[high]))
i++;
while (j >= low && !lessThan(S, indices[j], indices[high]))
j--;
if (i < j)
{
swap(indices[i], indices[j]);
i++;
j--;
}
}
swap(indices[high], indices[i]);
return i;
}

How to get the correct array dimensions to store all results for my DP memoization for N choose K problem?

I'm learning data-structures and algorithms, I can solve it recursively and I understand I have to add to a memo table to save repetitions, I'm having trouble doing it, some input would be very helpful. If you can also implement the set/ map solution, that would be great too, but I'm primarily looking for array solution for future reference. I think it might be because while passing the array, it's not passed by reference, because c++ doesn't do that, would a vector be a better choice? I tried, but wasn't able to make it work also. And array solution in Java which does pass arrays by reference is also not working, so I'm doing something wrong.
Code:
long long int combinMemo(int n, int k, int memo[]) {
if (k == 0) return 1;
if (n == k) return 1;
if(n < k || (n <= 0)) return 0;
if(memo[k] == 0) {
return memo[k] = (combinMemo(n - 1, k - 1, memo)) + combinMemo(n - 1, k, memo); //+ combinMemo(n - 1, k, memo));
} else {
return memo[k];
}
}
long long int combinMemoWrap(int n, int k) {
int memo[k + 1];
for(int i = 0; i < k + 1; i++) {
memo[i] = 0;
}
return combinMemo(n, k, memo);
}

I get a runtime error in my code of how to find if an array can be become non decreasing by modifying at most one element

Given an array with n integers, your task is to check if it could become non-decreasing by modifying at most 1 element.
We define an array is non-decreasing if array[i] <= array[i + 1] holds for every i (1 <= i < n).
My code is the one below. I get a runtime error while I run but I can not identify what the error is. I am quite new to programming so please specify in the simplest way possible if you find what goes wrong. Thank you.
class Solution {
public:
bool checkPossibility(vector<int> &nums) {
bool status = false;
int count = 0;
for (int i = 0; i <= nums.size() - 2; i++) {
if (nums[i] > nums[i + 1]) {
count++;
}
}
if (count > 1) {
status = false;
} else {
status = true;
}
return status;
}
};
I get a runtime overflow error.
nums.size() is unsigned. If the size is smaller than 2, size() - 2 will overflow and return a very large number, thus you will go out of bounds.
You can solve this simply by moving the 2 to the other side: i + 2 <= nums.size()

Code to find peak index of mountain array

You may recall that an array A is a mountain array if and only if: A.length >= 3
There exists some i with 0 < i < A.length - 1 such that:
A[0] < A[1] < ... A[i-1] < A[i]
A[i] > A[i+1] > ... > A[A.length - 1]
NOTES:
Array can be accessed using arr.get(index) function and its length = arr.length().
Test case it is failing is : (3,5,3,2,0).
Error : control reaches end of non void function.
My take:
I want to use binary search (with some modifications) to find the peak. Keeping in mind the above given conditions of mountain array, only 3 possibilities are there i.e. (point of increasing slope, point on peak, point on decreasing slope)
CODE:
int getPeak(MountainArray &arr, int left, int right)
{
int mid;
int mid_num;
int after_mid, before_mid;
mid = (left + right) / 2;
if (mid == 0)
{
return getPeak(arr, mid + 1, right);
} // to make sure i dont violate the range of array by calculating before_mid.mid_num = arr.get(mid);
after_mid = arr.get(mid + 1);
before_mid = arr.get(mid - 1);
if (before_mid < mid_num && mid_num < after_mid)
{
return getPeak(arr, mid + 1, right);
}
else if (mid_num > after_mid && mid_num > before_mid)
{
return mid;
}
else if (mid_num > after_mid && mid_num < before_mid)
{
return getPeak(arr, left, mid - 1);
}
}
You don't initialize mid_num, which causes undefined behavior. Add:
mid_num = arr.get(mid); // missing
after_mid = ...
...
BTW, when you find the local peak (second branch), you might want to additionally check that it is a global peak as well. As written, it would return index 2 for this array: {5,2,4,2,5}, which is not a mountain according to your definition.

Algorithm: Modified Binary Search

I am trying to tackle a classical interview problem which is basically performing a binary search on a list which first increases then decreases. Even though it's obvious that we can achieve O(log n) I couldn't figure out what is wrong the code below that I've written:
#include <iostream>
using namespace std;
int binarySearch(int *A, int low, int high, int key)
{
while(low < high)
{
int mid = (low + high) / 2;
if(key < A[mid])
{
if(A[mid - 1] < A[mid] && A[mid] < A[mid + 1])
high = mid - 1;
else
low = mid + 1;
}
else if(key > A[mid])
{
if(A[mid - 1] < A[mid] && A[mid] < A[mid + 1])
low = mid + 1;
else
high = mid - 1;
}
else
return mid;
}
return -(low + 1);
}
int main()
{
const int SIZE = 8;
int A[SIZE] = {3,5,7,14,9,8,2,1};
cout<<binarySearch(A, 0, SIZE, 14);
return 0;
}
The reason why I ask this question is because I wonder two things. 1) What is wrong with the code since it fails for some values such as "14". 2) Can it be improved?
I think your code does not handle well the increasing and decreasing part of the array.
Instead of telling you exactly how to do this, here is some tip and I hope you are able to finish it :)
One solution is to first find the point where the array goes from increasing order to decreasing order in O(logn), then based on that, perform a special version of binary search in O(logn).
Let me know in case you don't know how to to this, I will explain more on my answer.
Here is a more complete solution (served only as a reference)
One solution is to first find the point where the array goes from increasing order to decreasing order in O(logn), then based on that, perform a special version of binary search in O(logn).
The first part can be achieved by finding the last point where array[i-1] <= array[i] using a specialized binary search where the mid index moving condition is whether array[mid-1] <= array[mid] instead of whether array[mid] <= target.
Sample Code
To prevent me from being an interview hacker, below only shows how to handle an array without any duplicates. The code will soon removed if necessary:
#include <stdio.h>
#include <stdlib.h>
int find_change_point(int array[], int low, int high, int array_size) {
int mid;
for (mid = (low + high) / 2; low <= high; mid = (low + high) / 2) {
// if true, it implies the point is on the higher side
if (array[mid - 1] <= array[mid]) {
if (mid == array_size - 1) {
return mid;
}
// since we already handles equality, only > is needed.
if (array[mid] > array[mid + 1]) {
return mid;
}
low = mid + 1;
} else {
// then simply imply the point is on the lower part
high = mid - 1;
}
}
return mid;
}
int main() {
const int SIZE_1 = 8;
int array_1[SIZE_1] = {3,5,7,14,9,8,2,1};
int change_point = find_change_point(array_1, 0, SIZE_1 - 1, SIZE_1);
printf("change_point_1 = %d\n", change_point);
const int SIZE_2 = 9;
int array_2[SIZE_2] = {3,5,7,14,15,16,17,19, 20};
change_point = find_change_point(array_2, 0, SIZE_2 - 1, SIZE_2);
printf("change_point_2 = %d\n", change_point);
const int SIZE_3 = 9;
int array_3[SIZE_3] = {9, 8, 7, 6, 5, 4, 3, 2, 1};
change_point = find_change_point(array_3, 0, SIZE_3 - 1, SIZE_3);
printf("change_point_3 = %d\n", change_point);
}
and the output is:
change_point_1 = 3
change_point_2 = 8
change_point_3 = 0
For handling duplications, you need to find its left-end and right-end of the duplication sequence and verify whether they are increasing or decreasing sequence.
The second part has many varieties. One simple solution is to treat them as two arrays, and perform one binary search for each subarray to find your target element.
For your code i think to many branch like "if" operation .
Following is simple pseudocode for your reference:
while(1 < (high - low)){
int mid = (low + high) >> 1;
(key < A[mid]) ? high = mid : lo = mid;
}
return (key == A[lo]) ? lo : -1;
Hope this can be help you.