Hash Theory
In computing, a hash table (hash map) is a data structure used to implement an associative array, a structure that can map keys to values. A hash table uses a hash function to compute an index into an array of buckets or slots, from which the desired value can be found.
Insert a phone number and corresponding information.
Search a phone number and fetch the information.
Delete a phone number and related information.
Array of phone numbers and records.
Linked List of phone numbers and records.
Balanced binary search tree with phone numbers as keys.
Direct Access Table.
For arrays and linked lists, we need to search in a linear fashion, which can be costly in practice. If we use arrays and keep the data sorted, then a phone number can be searched in O(Logn) time using Binary Search, but insert and delete operations become costly as we have to maintain sorted order.
With balanced binary search tree, we get moderate search, insert and delete times. All of these operations can be guaranteed to be in O(Logn) time.
Hash Function: A function that converts a given big phone number to a small practical integer value. The mapped integer value is used as an index in hash table. In simple terms, a hash function maps a big number or string to a small integer that can be used as index in hash table. A good hash function should have following properties
Efficiently computable.
Should uniformly distribute the keys (Each table position equally likely for each key)
Hash Table: An array that stores pointers to records corresponding to a given phone number. An entry in hash table is NIL if no existing phone number has hash function value equal to the index for the entry.
Collision Handling: Since a hash function gets us a small number for a big key, there is possibility that two keys result in same value. The situation where a newly inserted key maps to an already occupied slot in hash table is called collision and must be handled using some collision handling technique. Following are the ways to handle collisions:
Chaining:The idea is to make each cell of hash table point to a linked list of records that have same hash function value. Chaining is simple, but requires additional memory outside the table.
Open Addressing: In open addressing, all elements are stored in the hash table itself. Each table entry contains either a record or NIL. When searching for an element, we one by one examine table slots until the desired element is found or it is clear that the element is not in the table.
Letter Combinations of a Phone Number
Given a digit string, return all possible letter combinations that the number could represent.
A mapping of digit to letters (just like on the telephone buttons) is given below.
Input:Digit string “23”
Output: [“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
class Solution {
public:
vector<string> letterCombinations(string digits) {
vector<string> res;
if (digits.empty()) return res;
vector<string> table = {"", "", "abc", "def", "ghi", "jkl","mno", "pqrs","tuv","wxyz"};
helper(digits, table, 0, "", res);
return res;
}
void helper(string digits, vector<string> table, int pos, string curr, vector<string> &res) {
if (pos == digits.size()) {
res.push_back(curr);
return;
}
for (int i=0; i<table[digits[pos]-'0'].size(); i++) {
helper(digits, table, pos+1, curr+table[digits[pos]-'0'][i], res);
}
}
};
Remove Duplicates from Sorted List
Given a sorted linked list, delete all duplicates such that each element appear only once.
For example,
Given 1->1->2, return 1->2.
Given 1->1->2->3->3, return 1->2->3.
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* prev = head;
while (prev) {
if (prev->next && prev->val == prev->next->val)
prev->next = prev->next->next;
else
prev = prev->next;
}
return head;
}
};
Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
For example,
Given 1->2->3->3->4->4->5, return 1->2->5.
Given 1->1->1->2->3, return 2->3.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* prevhead = new ListNode(0);
ListNode* prev = head;
ListNode* point = prevhead;
while (prev) {
if (prev->next && prev->val == prev->next->val)
while (prev->next && prev->val == prev->next->val)
prev = prev->next;
else {
point->next = prev;
point = point ->next;
}
prev = prev->next;
}
point->next = NULL;
return prevhead->next;
}
};
Remove Duplicates from Sorted Array
Given a sorted array, 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 in place with constant memory.
For example, Given input array 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 new length.
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if (nums.empty()) return 0;
int index = 0;
for (int i=1; i<nums.size(); i++) {
if (nums[i]!=nums[index])
nums[++index] = nums[i];
}
return index+1;
}
};
Follow up for “Remove Duplicates”: What if duplicates are allowed at most twice?
For example, Given sorted array nums = [1,1,1,2,2,3],
Your function should return length = 5, with the first five elements of nums being 1, 1, 2, 2 and 3. It doesn’t matter what you leave beyond the new length.
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int index = 1;
const int n = nums.size();
if (n<2) return n;
for (int i=1; i<n; i++) {
if (i+1<n && nums[i-1]==nums[i] && nums[i]==nums[i+1])
continue;
nums[index++] = nums[i];
}
return index;
}
};
Math Questions
Reverse digits of an integer.
Example1: x = 123, return 321
Example2: x = -123, return -321
class Solution {
public:
int reverse(int x) {
bool neg =false;
long y = x;
if (y<0)
{
y = -y;
neg = true;
}
long res = 0;
while (y)
{
res = res *10+y%10;
y /= 10;
}
if (!neg && res > INT_MAX || neg && -res < INT_MIN)
return 0;
return (neg)?-res:res;
}
};
Determine whether an integer is a palindrome. Do this without extra space.
class Solution {
public:
bool isPalindrome(int x) {
int val = 0;
int k = x;
if (x<0) return false;
while (k) {
int temp = k%10;
val = val*10 + temp;
k /= 10;
}
return val == x;
}
};
Given n non-negative integers a1, a2, …, an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
class Solution {
public:
int maxArea(vector<int>& nums) {
if (nums.empty()) return 0;
int left = 0, right = nums.size()-1;
int res = 0;
while (left<right) {
int temp = (right-left)*min(nums[left], nums[right]);
res = max(res, temp);
if (nums[left]<nums[right]) left++;
else right--;
}
return res;
}
};
Given a non-negative number represented as an array of digits, plus one to the number.
The digits are stored such that the most significant digit is at the head of the list.
class Solution {
public:
vector<int> plusOne(vector<int>& digits) {
for (int i=digits.size()-1; i>=0; i--) {
digits[i]++;
if (digits[i]<10) break;
digits[i] = 0;
}
if (digits[0]==0) {
digits[0] = 1;
digits.push_back(0);
}
return digits;
}
};
Given an unsorted integer array, find the first missing positive integer.
For example,
Given [1,2,0] return 3,
and [3,4,-1,1] return 2.
Your algorithm should run in O(n) time and uses constant space.
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
if (nums.empty()) return 1;
const int n = nums.size();
for (int i=0; i<n; i++)
while (nums[i]>0 && nums[i]<n && nums[nums[i]-1]!=nums[i])
swap(nums[i], nums[nums[i]-1]);
for (int i=0; i<n; i++)
if (nums[i] != i+1)
return i+1;
return n+1;
}
};
Binary Tree Series
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
class Solution {
public:
bool isEqual(TreeNode* p, TreeNode* q) {
if (!p && !q) return true;
if (!p || !q ||p->val != q->val) return false;
return isEqual(p->left, q->right) && isEqual(p->right, q->left);
}
bool isSymmetric(TreeNode* root) {
if (!root) return true;
return isEqual(root->left, root->right);
}
};
Invert a binary tree.
class Solution {
public:
TreeNode* invertTree(TreeNode* tree) {
if (!tree) return tree;
TreeNode* temp = tree->left;
tree->left = invertTree(tree->right);
tree->right = invertTree(temp);
return tree;
}
};
Given two binary trees, write a function to check if they are equal or not.
Two binary trees are considered equal if they are structurally identical and the nodes have the same value.
class Solution {
public:
int maxDepth(TreeNode* root) {
if (!root) return 0;
return max(1+maxDepth(root->left), 1+maxDepth(root->right));
}
};
Given a binary tree, find its maximum depth.
The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
class Solution {
public:
bool isSameTree(TreeNode* tree1, TreeNode* tree2) {
if (!tree1 && !tree2) return true;
if (!tree1 || !tree2 || tree1->val != tree2->val) return false;
return isSameTree(tree1->left, tree2->left) && isSameTree(tree1->right, tree2->right);
}
};