0. Basic Concepts
0.1 Two Pointers Type?
- Same direction pointers
- Face-to-face directions pointers
1. Problem Type:
1.1 Same direction pointers
When it comes to same direction pointers, two types of problems jump into my minds.
One the the sliding window problem: two pointers move right forward simultaneously, which usually go with the sum sub-array.
The other the truncation problem: this type of problem want you to remove the duplicate the elements etc, then the left pointer will record the current index, while the right pointer will iterate the array. When there is proper element, put it to the left pointer position. In this type of problem, left pointer index is usually the size of the new array.
1.1.1 Examples:
vector<int> winSum(vector<int> &nums, int k) {
// write your code here
vector<int> result;
// Inquery base case: what if the size of nums is less than k
if(nums.size() < k)
{
return result;
}
int l = 0, r = k-1;
int sum = 0;
for(int i = l; i <= r; i++)
{
sum += nums[i];
}
while(r < nums.size())
{
result.push_back(sum);
sum -= nums[l++];
sum += nums[++r];
}
return result;
}
void moveZeroes(vector<int> &nums) {
// write your code here
if(nums.empty() )
return;
int left = 0, right = 0;
int n = nums.size();
while(right < n) {
if(nums[right] == 0) {
right ++;
} else {
nums[left++] = nums[right++];
}
}
while(left < n ) {
nums[left++] = 0;
}
}
521. Remove Duplicate Numbers in Array
int deduplication(vector<int> &nums) {
// write your code here
if(nums.empty())
return 0;
sort(nums.begin(), nums.end() );
int left = 1, right = 1;
int n = nums.size();
while(right < n) {
if(nums[right] != nums[left -1]) {
nums[left++] = nums[right++];
} else {
right ++;
}
}
return left;
}
1.2 Face-to-face direction pointers
1.2.1 Examples:
bool isPalindrome(string &s) {
// write your code here
if(s.length() == 0)
return true;
int l = 0, r = s.length() -1;
while(l < r)
{
while(l < r && !isdigit(s[l]) && !isalpha(s[l]))
l++;
while(l < r && !isdigit(s[r]) && !isalpha(s[r]))
r--;
if(l < r && tolower(s[l++]) != tolower(s[r--])){
return false;
}
}
return true;
}
void rotateString(string &str,int offset){
//wirte your code here
int len = str.length();
if(len == 0 )
return;
offset = offset % len;
str = str.substr(len - offset) + str.substr(0, len - offset);
39. Recover Rotated Sorted Array
vector<int> tmp;
while(true)
{
tmp.push_back(nums[0]);
nums.erase(nums.begin());
if(nums.empty() || tmp.back() > nums[0] )
break;
}
for(auto now : tmp){
nums.push_back(now);
}
return;
1.3 2 Sum, 3 Sum
For 2 sum problem, which can also be two elements problem, it usually solved by hash table or two pointers. If the array is sorted, two pointers may have a better performance; If the array is not sorted, hash table/ hash set may be a better solution.
For 3 sum problem, which can also be three elements problem, it usually iterate one elements, and then perform two pointers methods.
1.3.1 Examples:
This version uses hash table.
vector<int> twoSum(vector<int> &numbers, int target) {
// write your code here
vector<int> result;
unordered_map<int, int> hash;
int n = numbers.size();
if(n == 0)
return result;
for(int i = 0; i < n; i++ ) {
int tmp = target - numbers[i];
if(hash.find(tmp) != hash.end() ) {
result.push_back(hash[tmp]);
result.push_back(i);
return result;
} else {
hash[numbers[i]] = i;
}
}
return result;
}
607. Two Sum III - Data structure design
Using hash set could have better performance
// using vector and hash table
class TwoSum {
private:
vector<int> nums;
public:
/**
* @param number: An integer
* @return: nothing
*/
void add(int number) {
// write your code here
nums.push_back(number);
}
/**
* @param value: An integer
* @return: Find if there exists any pair of numbers which sum is equal to the value.
*/
bool find(int value) {
// write your code here
unordered_map<int, int> hash;
for(int i = 0; i < nums.size(); i++) {
if(hash.count(nums[i])) {
return true;
} else {
hash[value - nums[i] ] = i;
}
}
return false;
}
};
// using hash set
class TwoSum {
public:
unordered_multiset<int> nums;
// Add the number to an internal data structure.
void add(int number) {
// Write your code here
nums.insert(number);
}
// Find if there exists any pair of numbers which sum is equal to the value.
bool find(int value) {
// Write your code here
for (int i : nums) {
int count = i == value - i ? 2 : 1;
if (nums.count(value - i) >= count) {
return true;
}
}
return false;
}
};
608. Two Sum II - Input array is sorted
class Solution {
public:
/**
* @param nums: an array of Integer
* @param target: target = nums[index1] + nums[index2]
* @return: [index1 + 1, index2 + 1] (index1 < index2)
*/
vector<int> twoSum(vector<int> &nums, int target) {
// write your code here
int left = 0, right = nums.size() -1;
vector<int> result {-1, -1};
if(right <= 0)
return result;
while(left < right && right < nums.size()) {
int sum = nums[left] + nums[right];
if(sum == target) {
result[0] = left +1;
result[1] = right +1;
return result;
}
if(sum < target) {
left++;
}
if(sum > target) {
right --;
}
}
return result;
}
};
587. Two Sum - Unique pairs
Sort the array first.
int twoSum6(vector<int> &nums, int target) {
// write your code here
int n = nums.size();
if(nums.empty() )
return 0;
sort(nums.begin(), nums.end() );
int cnt = 0;
int left = 0, right = n -1;
while(left < right) {
int sum = nums[left] + nums[right];
if(sum == target) {
cnt++;
// move on to next number
left ++;
// if there is duplicate, move forward
while(nums[left] == nums[left -1])
left ++;
}
if(sum < target) {
left ++;
while(nums[left] == nums[left -1])
left ++;
}
if(sum > target) {
right --;
while(nums[right] == nums[right +1])
right --;
}
}
return cnt;
}
vector<vector<int>> threeSum(vector<int> &nums) {
// write your code here
vector<vector<int>> result;
if(nums.empty() )
return result;
sort(nums.begin(), nums.end() );
for(int i = 0; i < nums.size() -2;) {
int left = i + 1, right = nums.size() -1;
while(left < right ) {
int sum = nums[left] + nums[right] + nums[i];
if(sum == 0) {
result.push_back(vector<int> {nums[i], nums[left], nums[right]});
left++;
while(nums[left] == nums[left -1])
left++;
}
if(sum > 0) {
right --;
while(nums[right] == nums[right +1])
right--;
}
if(sum < 0) {
left++;
while(nums[left] == nums[left -1])
left++;
}
}
i++;
while(nums[i] == nums[i -1])
i++;
}
return result;
}
Let the a, b, c be the edges of a triangle, and c is the longest edges.
In this 3 elements problem, we iterate the edge c, and perform two pointers method on a and b.
int triangleCount(vector<int> &nums) {
// write your code here
sort(nums.begin(), nums.end());
int result = 0;
int begin, end;
for(int i = nums.size() -1; i > 0; i--)
{
begin = 0, end = i-1;
while(begin < end)
{
if(nums[begin] + nums[end] > nums[i])
{
result += (end - begin);
end--;
}
else {
begin++;
}
}
}
return result;
}
443. Two Sum - Greater than target
int twoSum2(vector<int> &nums, int target) {
// write your code here
int n = nums.size();
if(nums.empty() )
return 0;
int cnt = 0;
sort(nums.begin(), nums.end() );
int left = 0, right = n -1;
while(left < right ) {
if(nums[left] + nums[right] > target) {
cnt += (right - left);
right --;
} else {
left ++;
}
}
return cnt;
}
609. Two Sum - Less than or equal to target
int twoSum5(vector<int> &nums, int target) {
// write your code here
int n = nums.size();
if(nums.empty() )
return 0;
int cnt = 0;
sort(nums.begin(), nums.end() );
int left = 0, right = n -1;
while(left < right ) {
if(nums[left] + nums[right] <= target) {
cnt += (right - left);
left ++;
} else {
right --;
}
}
return cnt;
}
533. Two Sum - Closest to target
int twoSumClosest(vector<int> &nums, int target) {
// write your code here
int result = INT_MAX;
if(nums.empty() || nums.size() == 1)
{
return result;
}
sort(nums.begin(), nums.end());
int begin = 0, end = nums.size() -1;
while(begin < end)
{
int sum = nums[begin] + nums[end];
if(sum < target)
{
result = abs(sum - target) < result? abs(sum - target) : result;
begin++;
}
else{
result = abs(sum - target) < result? abs(sum - target) : result;
end--;
}
}
return result;
}
int threeSumClosest(vector<int> &nums, int target) {
// write your code here
if(nums.empty() )
return target;
int diff = INT_MAX, result;
sort(nums.begin(), nums.end() );
for(int i = 0; i < nums.size(); i++ ) {
int left = i +1, right = nums.size() -1;
while(left < right) {
int sum = nums[i] + nums[left] + nums[right];
if(sum > target) {
if(abs(sum - target) < diff) {
diff = abs(sum - target);
result = sum;
}
right --;
} else {
if(abs(sum - target) < diff) {
diff = abs(sum - target);
result = sum;
}
left ++;
}
}
}
return result;
}
vector<vector<int>> fourSum(vector<int> &nums, int target) {
// write your code here
vector<vector<int>> result;
if(nums.empty() || nums.size() < 4 )
return result;
sort(nums.begin(), nums.end()) ;
int left, right;
for(int i = 0; i < nums.size() -3; ) {
for(int j = i +1; j < nums.size() -2;) {
left = j +1, right = nums.size() -1;
while(left < right) {
int sum = nums[i] + nums[j] + nums[left] + nums[right];
if(sum == target) {
result.push_back(vector<int> {nums[i], nums[j], nums[left], nums[right]} );
left++;
while(nums[left] == nums[left -1])
left++;
}
if(sum < target ) {
left++;
while(nums[left] == nums[left -1])
left++;
}
if(sum > target) {
right --;
while(nums[right] == nums[right +1])
right--;
}
}
j++;
while(nums[j] == nums[j -1])
j++;
}
i++;
while(nums[i] == nums[i -1])
i++;
}
return result;
}
610. Two Sum - Difference equals to target
vector<int> twoSum7(vector<int> &nums, int target) {
// write your code here
vector<int> result;
unordered_map<int, int> hashMap;
int n = nums.size();
for (int i = 0; i < n; i++) {
int tmp = nums[i] - target;
if (hashMap.find(tmp) != hashMap.end()) {
result.push_back(hashMap[tmp] + 1);
result.push_back(i + 1);
return result;
}
tmp = nums[i] + target;
if (hashMap.find(tmp) != hashMap.end()) {
result.push_back(hashMap[tmp] + 1);
result.push_back(i + 1);
return result;
}
hashMap[nums[i]] = i;
}
}
1.4 Partition Array
1.4.1 Examples:
int partitionArray(vector<int> &nums, int k) {
// write your code here
int left = 0, right = nums.size() -1;
while(left <= right) {
while(nums[left] < k)
left ++;
while(nums[right] >= k)
right --;
if(left <= right) {
int tmp = nums[left];
nums[left] = nums[right];
nums[right] = tmp;
left ++;
right --;
}
}
return left;
}
461. Kth Smallest Numbers in Unsorted Array
class Solution {
public:
/*
* @param k an integer
* @param nums an integer array
* @return kth smallest element
*/
int kthSmallest(int k, vector<int> nums) {
return quickSelect(nums, 0, nums.size() - 1, k - 1);
}
int quickSelect(vector<int>& A, int start, int end , int k) {
if (start == end)
return A[start];
int left = start, right = end;
int pivot = A[(start + end) / 2];
while (left <= right) {
while (left <= right && A[left] < pivot) {
left++;
}
while (left <= right && A[right] > pivot) {
right--;
}
if (left <= right) {
swap(A[left++], A[right--]);
}
}
if (right >= k && start <= right)
return quickSelect(A, start, right, k);
else if (left <= k && left <= end)
return quickSelect(A, left, end, k);
else
return A[k];
}
};
class Solution {
public:
/*
* @param chars: The letter array you should sort by Case
* @return: nothing
*/
bool isLower(char c)
{
return c >= 'a' && c <= 'z';
}
void sortLetters(string &str) {
// write your code here
int start = 0, end = str.length() -1;
while(start <= end)
{
while(start <= end && isLower(str[start]))
start++;
while(start <= end && !isLower(str[end]))
end--;
if(start <= end)
{
char tmp = str[start];
str[start] = str[end];
str[end] = tmp;
}
}
}
};
373. Partition Array by Odd and Even
void partitionArray(vector<int> &nums) {
// write your code here
int start = 0, end = nums.size() -1;
while(start <= end)
{
while(nums[start] % 2 == 1)
start++;
while(nums[end] %2 == 0)
end --;
if(start <= end) {
int tmp = nums[start];
nums[start] = nums[end];
nums[end] = tmp;
}
}
}
144. Interleaving Positive and Negative Numbers
class Solution {
public:
/**
* @param A: An integer array.
* @return: void
*/
vector<int> subfun(vector<int> &A, vector<int> &B) {
vector<int> ans;
for(int i = 0; i < B.size(); i++) {
ans.push_back(A[i]);
ans.push_back(B[i]);
}
if(A.size() > B.size())
ans.push_back(A[B.size()]);
return ans;
}
void rerange(vector<int> &A) {
// write your code here
vector<int> Am, Ap, tmp;
for(int i = 0; i < A.size(); i++)
if(A[i] > 0)
Ap.push_back(A[i]);
else
Am.push_back(A[i]);
if(Ap.size() > Am.size())
tmp = subfun(Ap, Am);
else
tmp = subfun(Am, Ap);
for (int i = 0; i < tmp.size(); ++i)
A[i] = tmp[i];
}
};
148. Sort Colors
Three pointers problem.
void sortColors(vector<int> &nums) {
int left = 0, right = nums.size() - 1;
int middle = 0;
// should be <= not <
while (middle <= right) {
if (nums[middle] == 0) {
swap(nums[middle], nums[left]);
left++;
middle++;
} else if (nums[middle] == 1) {
middle++;
} else {
swap(nums[middle], nums[right]);
right--;
}
}
}
One solution: Bucket Sorting
void sortColors2(vector<int> &colors, int k) {
// write your code here
vector<int> count(k +1);
for(auto num : colors)
count[num] ++;
int index = 1;
for(int i = 0; i < colors.size(); i++) {
while(count[index] == 0) {
index ++;
}
colors[i] = index ;
count[index] --;
}
}
Another Solution: divide and conquer
class Solution {
public:
/**
* @param colors: A list of integer
* @param k: An integer
* @return: nothing
*/
void sortColors2(vector<int> &colors, int k) {
// write your code here
partition(colors, 0, colors.size()-1, 1, k);
}
void partition(vector<int>& colors, int start, int end, int startk, int endk) {
if (start >= end || startk >= endk) {
return;
}
int midk = (startk+endk)/2;
int i = start, j = end;
while (i <= j) {
while (i <= j && colors[i] <= midk) {
i++;
}
while (i <= j && colors[j] > midk) {
j--;
}
if (i <= j) {
int temp = colors[j];
colors[j] = colors[i];
colors[i] = temp;
i++;
j--;
}
}
partition(colors, start, j, startk, midk);
partition(colors, i, end, midk+1, endk);
}
};