26. Remove Duplicates from Sorted Array
Given a sorted array nums, remove the duplicates in-place such that
each element appear only once and return the new length.
Do not allocate extra space for another array, you must do this by
modifying the input array in-place with O(1) extra memory.
Example 1:
Given nums = [1,1,2],
Your function should return length = 2, with the first two elements of
nums being 1 and 2 respectively.
It doesn't matter what you leave beyond the returned length. Example
2:
Given `nums = [0,0,1,1,1,2,2,3,3,4],
Your function should return length = 5, with the first five elements
of nums being modified to 0, 1, 2, 3, and 4 respectively.
It doesn't matter what values are set beyond the returned length.
Clarification:
Confused why the returned value is an integer but your answer is an
array?
Note that the input array is passed in by reference, which means
modification to the input array will be known to the caller as well.
Internally you can think of this:
// nums is passed in by
reference. (i.e., without making a copy) int len =
removeDuplicates(nums);
// any modification to nums in your function would be known by the
caller. // using the length returned by your function, it prints the
first len elements. for (int i = 0; i < len; i++) {
print(nums[i]); }
i am getting this runtime error while submitting it on leetcode it works fine on coding blocks but shows this error in leetcode compilor
Line 924: Char 9: runtime error: reference binding to null pointer of type 'int' (stl_vector.h)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/stl_vector.h:933:9
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int k=nums[0];
for(auto i=nums.begin()+1;i<nums.end();i++)
{
if(*i==k) nums.erase(i) , i--;
else k=*i;
}
return nums.size();
}
};
Can anybody help me in finding the cause of error?
Your code works just fine, missing one edge case (an empty nums):
if (nums.empty()) {
return 0;
}
Updated Code:
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if (nums.empty()) {
return 0;
}
int k = nums[0];
for (auto i = nums.begin() + 1; i < nums.end(); i++) {
if (*i == k) {
nums.erase(i) , i--;
}
else {
k = *i;
}
}
return nums.size();
}
};
Maybe we could just write a simple loop using size(). This'd pass on LeetCode:
// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <vector>
// Start
static const struct Solution {
using SizeType = std::uint_fast16_t;
static const int removeDuplicates(
std::vector<int>& nums
) {
const SizeType len = std::size(nums);
SizeType count = 0;
for (SizeType i = 1; i < len; ++i) {
if (nums[i] == nums[i - 1]) {
++count;
} else {
nums[i - count] = nums[i];
}
}
return len - count;
}
};
Related
I am writing a function CreateGrid() that is trying to take a std::string and a 2d std::array as parameters, and put the individual characters from the std::string into the array. The rest of the array, if space is left, should be filled with the alphabetical characters A-Y, inclusive, in alphabetical order, providing they do not already appear in the std::string. Each character should only appear once in the final returned array.
So for input string keyword = "HELO";
The output would be:
H E L
O A B
C D F
Note the char 'E' only appears once.
I am trying to use std::find() to test whether all the chars in the alphabet A-Y (Z intentionally excluded) is already in the array, due to the keyword, before inserting it if it is not so that there are no duplicates. I am getting a compile error.
Code:
array<array<char,3>,3> CreateGrid(std::string keyword, array<array<char,3>,3> myArray)
{
char letterToFind = 'A';
for (int row = (keywordLength/3); row < 3; row++ )
{
for (int column = (keywordLength % 3); column < 3; column++)
{
auto it = std::find(begin(myArray), end(myArray), letterToFind);
if ( it == end(myArray) ) // value not in array
{
myArray[row][column] = letterToFind; //insert
}
letterToFind++;
}
}
return myArray;
}
int main()
{
array<array<char,3>,3> myArray = { {'H','E','L'}, {'O','+','+'}, {'+','+','+'} };
CreateGrid("HELO", myArray);
return 0;
}
I get a compile error for this line:
auto it = std::find(begin(myArray), end(myArray), letterToFind);
message : see reference to function template instantiation '_InIt std::find<std::_Array_iterator<_Ty,5>,char>(_InIt,const _InIt,const char &)' being compiled with[_InIt=std::_Array_iterator<std::array<char,3>3>,_Ty=std::array<char,3>]
How do I check to see if a char is in the array already, and if not then add it?
This is not normally trivial since you have nested arrays. std::find can only return an iterator to the outer array, which isn't useful if you need to change the value in the inner array.
However, I notice that you don't actually use it other than to see if the sought element was located. So, we can redefine the operation: instead of finding the element in an inner array that contains the value, it's sufficient to find any inner array that contains the value you're looking for:
auto it = std::find(
begin(myArray), end(myArray),
[letterToFind](array<char,3> const & inner) {
return std::find(begin(inner), end(inner), letterToFind) != end(inner);
}
);
If you found such an inner array, then you know that the value exists in the 2d array and can proceed.
Since you don't need the iterator, you could also use std::any_of instead:
bool found = std::any_of(
begin(myArray), end(myArray),
[letterToFind](array<char,3> const & inner) {
return std::find(begin(inner), end(inner), letterToFind) != end(inner);
}
);
Your myArray parameter is an array containing array<char,3> elements. You are using find() to search only that outer array. So begin(myArray) will return an iterator that enumerates array<char,3> elements, and you can't compare a single char to a whole array<char,3>, which is why your find() call does not compile. You would have to loop though the outer array calling find() on each inner array instead.
A simpler way to implement this is to use a lookup table to keep track of the characters that you have already seen, eg:
const size_t MaxRows = 3;
const size_t MaxColumns = 3;
const size_t MaxCells = MaxRows * MaxColumns;
using gridRow = std::array<char, MaxColumns>;
using grid = std::array<gridRow, MaxRows>;
grid CreateGrid(const std::string &keyword)
{
grid g;
std::array<bool, 256> lookup{};
size_t numFilled = 0;
for(size_t i = 0; (i < keyword.size()) && (numFilled < MaxCells); ++i)
{
if (!lookup[static_cast<unsigned char>(keyword[i])])
{
lookup[static_cast<unsigned char>(keyword[i])] = true;
g[numFilled / 3][numFilled % 3] = keyword[i];
++numFilled;
}
}
for(char ch = 'A'; (ch <= 'Y') && (numFilled < MaxCells); ++ch)
{
if (!lookup[static_cast<unsigned char>(ch)])
{
g[numFilled / 3][numFilled % 3] = ch;
++numFilled;
}
}
return g;
}
int main()
{
grid myArray = CreateGrid("HELO");
...
return 0;
}
Live Demo
Alternatively, you can use a std::set or std::unordered_set for the lookup:
#include <unordered_set>
const size_t MaxRows = 3;
const size_t MaxColumns = 3;
const size_t MaxCells = MaxRows * MaxColumns;
using gridRow = std::array<char, MaxColumns>;
using grid = std::array<gridRow, MaxRows>;
grid CreateGrid(const std::string &keyword)
{
grid g;
std::unordered_set<char> lookup;
size_t numFilled = 0;
for(size_t i = 0; (i < keyword.size()) && (numFilled < MaxCells); ++i)
{
if (lookup.insert(keyword[i]).second)
{
g[numFilled / 3][numFilled % 3] = keyword[i];
++numFilled;
}
}
for(char ch = 'A'; (ch <= 'Y') && (numFilled < MaxCells); ++ch)
{
if (lookup.insert(ch).second)
{
g[numFilled / 3][numFilled % 3] = ch;
++numFilled;
}
}
return g;
}
int main()
{
grid myArray = CreateGrid("HELO");
...
return 0;
}
Live Demo
Trying to understand the insertion sort algorithm..
My algorithm looks like this currently:
void insertionSort(int *array, int N) {
int value;
int hole;
int *array2;
for (int i = 1; i < N - 1; i++) {
value = array[i]; //next item to be inserted in array 2
hole = i;
while (hole > 0 && array[hole - 1] > value) {
array[hole] = array[hole - 1];
hole = hole - 1;
}
array[hole] = value;
}
}
My algorithm works for sorting arrays, however I now need to change it so that I build up a new sorted array (array2) one element at a time, rather than just working with the original array.
Is there a simple way to implement this given my completed algorithm?
Thanks.
You can use the following method:
int *array2 = calloc(N, sizeof(int));
for(var index = 0; index < N; index++)
{
array2[index] = array[index];
}
and after that use array2 instead of array
then just change the prototype of your function to int *insertionSort
All remaining is to return array2 at the end of task
But be aware of memory leak: https://en.wikipedia.org/wiki/Memory_leak
For some reason, my function LinearSearch is only getting the first element of the array that's being passed in. I found this by putting a breakpoint in the function and looking at the locals that it has, and I don't know why it's only getting the 7 from the array a. The test case I have is the following (GoogleTest):
TEST(LinearSearch, ElementExists2Items) {
// LinearSearch should return a pointer to the item if it exists in the array.
int a[2] = {7, 2};
EXPECT_EQ(a, LinearSearch(a, 2, 7));
EXPECT_EQ(a + 1, LinearSearch(a, 2, 2));
}
Here is my LinearSearch function:
int* LinearSearch(int theArray[], int size, int key) {
if (size == 0)
return nullptr;
for (int i = 0; i < size; i++) {
if (key == theArray[i])
return (theArray);
else
return nullptr;
}
}
Am I missing something? Do I need to pass theArray by reference instead? I don't know why it's only getting the first value passed into the function.
You are returning the very first time.
Solution or rather a hint
for (int i = 0; i < size; i++) {
if (key == theArray[i])
return (theArray);
//if it cannot find it the very first time, it returns null IN YOUR CASE :)
}
return nullptr;
Your Case
Just think about the execution. The very first time it does not find something it immediately returns and exits the function. Hence it only sees one element.
for (int i = 0; i < size; i++) {
if (key == theArray[i])
return (theArray);
else
return nullptr;
}
Update
for (int i = 0; i < size; i++) {
if (key == theArray[i])
return (theArray + i);
// you currently pass the pointer to the start of the array again and again. Pass the pointer to the element instead.
}
return null;
I was trying to solve the following problem,
Given an array of integers, every element appears three times except
for one. Find that single one.
When the input are all positive, I will not get any errors, but when the input contains negative integers, the line delete index; will give error, does anybody know why?
i.e.
A[] = {1,2,3,4,1,2,3,4,1,3,4} works fine, but A[] = {-2,-2,1,1,-3,1,-3,-3,-4,-2} does not.
The code is as follow,
#include <iostream>
#include <map>
class Solution {
public:
int singleNumber(int A[], int n) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
int *index;
std::map<int, int> m;
index = new signed int[(n+1)/3];
int flag = 0;
int result;
for(int i=0; i<n; i++) {
if(m.find(A[i]) == m.end()) {
m[A[i]] = 1;
index[flag] = A[i];
flag++;
} else {
m[A[i]] = m[A[i]] + 1;
}
}
for(int i=0; i<(n+1)/3; i++) {
if(m[index[i]] != 3) {
result = index[i];
}
}
delete index;
return result;
}
};
int main()
{
Solution s;
int A[] = {1,2,3,4,1,2,3,4,1,3,4};
int result = s.singleNumber(A, 11);
std::cout <<result;
return 0;
}
The first array contains 11 elements, which causes the line index = new signed int[(n+1)/3]; to allocate an array of (11+1)/3 = 4 elements. The second array contains 10 elements, which causes that line to allocate an array of (10+1)/3 = 3 elements.
3 elements is insufficient to record the unique values in A (-4, -3, -2, and 1), so you overflow the array.
You should allocate at least (n+2)/3 elements. It would also be prudent to test the value of flag to ensure it never exceeds the array bounds. It will not if the input array obeys the constraint that every element but one appears three times (presuming this means it will appear one or two times, not four or more), but can you rely on that constraint being obeyed?
Additionally, the loop for(int i=0; i<(n+2)/3; i++) is insufficient to iterate through all the elements that were added to the map. You should be sure you iterate through all the members of m.
Incidentally, singleNumber can be implemented in a much more fun way without any dynamic allocation or library calls:
int singleNumber(int A[], int n) {
int b = 0, c = 0;
while (n--)
{
b ^= A[n] & c;
c ^= A[n] & ~b;
}
return c;
}
However, this is completely not what your instructor is expecting.
EDIT : Added far more detail.
I'm trying to write an algorithm that finds the intersection (points common to all) of n arrays. My program takes these arrays and stores them in a two dimensional array on which the operations take place. For example, here is a sample main method:
int a[] = { 12, 54, 42 };
int b[] = { 54, 3, 42, 7 };
int c[] = { 3, 42, 54, 57, 3 };
IntersectionTableau<int> x(3); // Where 3 is the max number of arrays allowed
// to be stored.
x.addArray(a, 3);
x.addArray(b, 4);
x.addArray(c, 9);
x.run(); // Finds the intersection.
These added arrays will be stored in T** arrays and their sizes in int* sizes. T is a generic type. What is an efficient algorithm that will let me do this on a variable number of arrays of generic types?
Here is what I'm currently attempting to do:
template <class T>
inline
void IntersectionTableau<T>::run() {
T* commonElements = d_arrays[0];
for (int i = 1; i < d_currentNumberOfArrays; ++i) {
commonElements = getIntersection(commonElements, d_arrays[i], d_sizes[i - 1], d_sizes[i]);
}
d_results = commonElements;
}
template <class T>
inline
T* IntersectionTableau<T>::getIntersection(T* first, T* second, int sizeOfFirst, int sizeOfSecond) {
T* commonElements;
if (sizeOfFirst > sizeOfSecond) {
commonElements = new T[sizeOfFirst];
} else {
commonElements = new T[sizeOfSecond];
}
for (int i = 0; i < sizeOfFirst; ++i) {
for (int j = 0; j < sizeOfSecond; ++j) {
if (first[i] == second[i]) {
commonElements[i] = first[i];
}
}
}
return commonElements;
}
The first function takes the first two arrays and sends them to the second function, which returns an array of the intersections between those two arrays. Then, the first function compares the intersection array with the next array in d_arrays and so on. My problem is when I go to print out an element from d_results a garbage value is produced, and I'm unsure why. Could someone tell me what I'm doing wrong, or alternatively, a better way to accomplish this?
There are at least two problems in the code:
if (first[i] == second[i])
This should be if (first[i] == second[j]).
commonElements[i] = first[i];
This is trickier to fix. I think you want to have another variable (neither i nor j); let's call it k:
commonElements[k++] = first[i];
Anyway, since you can use C++, you can use a std::vector instead. It stores its size inside; this will reduce confusion:
template <class T>
std::vector<T> // note: adjusted the return type!
IntersectionTableau<T>::getIntersection(...)
{
std::vector<T> commonElements;
for (int i = 0; i < sizeOfFirst; ++i) {
for (int j = 0; j < sizeOfSecond; ++j) {
if (first[i] == second[j]) {
commonElements.push_back(first[i]);
}
}
}
return commonElements;
}
You can turn first and second into vectors too (though you won't benefit much from it right now).
Here are some points to note:
I changed the return type to vector<T>
The old version, which returns an array, requires additional code to specify the length of its result; this version returns the length inside the vector<T> object
The old version, which returns an array, requires delete[] array somewhere later, to prevent a memory leak
The vector-to-pointer hack &commonElements[0] will not work for an empty vector
If your other code works with an array/pointer, you can use the vector-to-pointer hack &commonElements[0], but outside the function, in order to respect the lifetime rules:
T* commonElements = NULL;
for (int whatever = 0; whatever < 10; ++whatever)
{
std::vector<T> elements = xxx.getIntersection(...); // will work
commonElements = &elements[0]; // can pass this pointer to a function receiving T*
print(commonElements); // will work
}
print(commonElements); // cannot possibly work, will probably segfault
print(elements); // cannot possibly work, and compiler will reject this