Adobe is one of the most sought after companies by software developers owing to its collaborative and supportive culture and worldwide recognition as a global leader in powering digital businesses. Every year Adobe provides diverse job opportunities for software engineers, developers, engineering managers, and other applicants. To nail the opportunity at Adobe, software specialists must brace up for the most challenging Adobe coding interview questions with strong preparation and consistent practice.
About Adobe
Founded in 1982, Adobe is an American computer software company headquartered in San Jose, California. The company is behind pioneering the papertodigital transformation by introducing the world to PDF files. Currently, it employs 26000+ skilled professionals worldwide. Expanding into digital marketing software, Adobe has secured its position as one of the top global leaders in Customer Experience Management.
Adobe Products
Adobe establishes a connection between content and data by introducing newer technologies democratizing creativity, shaping the next generation with AI, and inspiring digital businesses worldwide. Different Adobe solutions are available under the SaaS packages. Its wide range of products includes:
Creativity and Design 
Marketing and Commerce 
Additional Solutions 



Adobe Interview Process
Adobe creates software that benefits students, filmmakers, and designers to grow and compete to prove their stand. Not only this but the company is also known for its supportive and collaborative culture. Adobe believes in inclusion and diversity at different levels to allow creative minds to step out of the sphere.
To fill positions on its technological team, Adobe employs both recent graduates and established workers. Currently, Adobe maintains offices in 75 different countries throughout the globe. Adobe has seven operations in India, with its technical teams based in the Noida and Bangalore locations, respectively.
Interview Process

For Freshers
In addition to campus placement (at Tier 1 institutions) and offcampus recruitment drives, Adobe also employs freshers. The following are the major procedures that are followed in the recruiting of Adobe freshers.
 Campus visit or application via a career portal or recruiting agency
 CV evaluation
 Written exam for Adobe's entrylevel hiring. This entails creating pseudocode and occasionally essaystyle questions
 Multiple technical interview rounds
 HR discussions

For Experienced
Adobe recruits experienced professionals for a variety of positions on its technical and product development teams at its Noida and Bangalore headquarters in India, as well as its international offices. Here is Adobe's procedure for employing experienced workers.
 Resume evaluation for Adobe position
 Telephone conversation (pretechnical round)
 Online coding assignment
 Adobe's technical interviews
 Human Resources round

CV Shortlisting Procedure
During the CV screening process, Adobe has stringent requirements. In the CV screening process, there are many factors that they look for.
 In India, Adobe employs the criterion of shortlisting individuals who have earned a grade point average of 7.0 or above throughout their educational career.
 There should be no educational backlogs on the part of the applicants.
 Candidates with a solid understanding of computer science, problemsolving abilities, and a love for coding are preferred. Candidates should have proved their technical competence in their previous work or projects to be considered.

Online Coding Round at Adobe
Having passed the CV screening round, applicants seeking offcampus placement and experienced professionals will be asked to show their technical ability in an Online coding round to be considered for placement.
Interview Rounds

Phone Screenings
You'll learn about the firm and the job you've applied for during the phone interview. In order to comprehend your job experience, technical expertise, and talents, recruiters may ask you a few questions.

A Phone Interview With a Hiring Manager
After that, you'll meet with a recruiter. You'll be tested on your ability to solve problems, lead others, and fit in with the company's culture, all of which are reflected in your CV.

Technical Assessment
You'll get an email with a link to a 65question online technical exam once you pass the phone screen.
 Aptitude and Logic (45 questions, 45 minutes): To see how well you can reason quantitatively and logically.
 Technical and Coding (1520 questions, 75120 mins): To put your knowledge of algorithms, data structures, and bit manipulation to the ultimate test. Adobe's favored languages are C, C++, and Java, although you may take the exam in any language you like.

Onsite Interview
Finalround interviews at Adobe are being carried out remotely rather than in person due to the pandemic. There are four stages of technical screenings and one HR interview during the onsite interviews.
There are two technologyrelated interviews:
 Interview on System Design
 Interview on ObjectOriented Design
During these interviews, you will be asked to write code on a whiteboard and explain your thinking process and why you picked a certain programming language to solve a problem.

HR Round
This round will consist of behavioral and contextual questions that will allow you to be assessed on your fundamental values as well as your work dynamics.
Adobe Coding Questions
If you want to get placed in Adobe, then the toughest hurdle to tackle is undoubtedly the Interview round at Adobe. To clear this technical interview, you need to prepare with some hot questions which are more likely to come up for you.
Arrays
1. Given an array of integers and a value, find out if there are three integers in the array whose sum will equal the given value.
Code Part
 Language: C++
bool find_sum_of_two(vector<int>& A, int val,
size_t start_index) {
for (int i = start_index, j = A.size()  1; i < j;) {
int sum = A[i] + A[j];
if (sum == val) {
return true;
}
if (sum < val) {
++i;
} else {
j;
}
}
return false;
}
bool find_sum_of_three_v3(vector<int> arr,
int required_sum) {
std::sort(arr.begin(), arr.end());
for (int i = 0; i < arr.size()  2; ++i) {
int remaining_sum = required_sum  arr[i];
if (find_sum_of_two(arr, remaining_sum, i + 1)) {
return true;
}
}
return false;
}
int main(){
vector<int> arr = {25, 10, 7, 3, 2, 4, 8, 10};
cout<<"8: " <<find_sum_of_three_v3(arr, 8)<<endl;
cout<<"25: "<<find_sum_of_three_v3(arr, 25)<<endl;
cout<<"0: " <<find_sum_of_three_v3(arr, 0)<<endl;
cout<<"42: " <<find_sum_of_three_v3(arr, 42)<<endl;
cout<<"22: " <<find_sum_of_three_v3(arr, 22)<<endl;
cout<<"7: " <<find_sum_of_three_v3(arr, 7)<<endl;
cout<<"3: " <<find_sum_of_three_v3(arr, 3)<<endl;
cout<<"2: " <<find_sum_of_three_v3(arr, 2)<<endl;
cout<<"4: " <<find_sum_of_three_v3(arr, 4)<<endl;
cout<<"8: " <<find_sum_of_three_v3(arr, 8)<<endl;
cout<<"7: " <<find_sum_of_three_v3(arr, 7)<<endl;
cout<<"1: " <<find_sum_of_three_v3(arr, 1)<<endl;
return 0;
}
 Explanation
Here we have to sort the array first. After that, we set one element ‘e,’ and from the remaining array, we try to find a pair (a, b) such that it fulfills the criteria: required_sum  e = a + b.
The search begins with the first element e in the array (at index i = 0). The above code will find such a pair in linear time. The time we find the required pair, we find the solution: a, b, and e, after which the iteration stops.
However, if the pair is not found, the above steps will repeat for all elements from index i = 1 to n  3 until the conditions are met.
2. If an array containing 'n' distinct numbers is taken from 0 to 'n,' the array will only have 'n' numbers out of the 'n+1' numbers. Find the missing number.
Code Part
 Language: C++
int find_missing(const vector<int>& input) {
auto sum_of_elements = std::accumulate(
input.begin(), input.end(), 0);
int n = input.size() + 1;
int actual_sum = (n * ( n + 1 ) ) / 2;
return actual_sum  sum_of_elements;
}
void test(int n) {
int missing_element = rand() % n + 1;
vector<int> v;
for (int i = 1; i <= n; ++i) {
if (i == missing_element) {
continue;
}
v.push_back(i);
}
int actual_missing = find_missing(v);
cout << "Expected Missing = " << missing_element << " Actual Missing = " << actual_missing << endl;
}
int main() {
srand (time(NULL));
for (int i = 1; i < 10; ++i)
test(100000);
return 0;
}
 Explanation
The above code will simply search for every integer present between 1 and n in the input array. The search will stop when there's a missing number. As the input array contains random values, not sorted values, the time complexity will be O(n2).
Linked List
3. If you're given the head pointers of two linked lists and each linked list refers to an integer number (where each node is a digit), add them and return the resulting linked list.
Code Part
 Language: Python
def add_integers(integer1, integer2):
result = None
last = None
carry = 0
while (integer1 != None or integer2 != None or carry > 0):
first = (0 if integer1 == None else integer1.data)
second = (0 if integer2 == None else integer2.data)
sum = first + second + carry
pNew = LinkedListNode(sum % 10)
carry = sum // 10
if result == None:
result = pNew
else:
last.next = pNew
last = pNew
if integer1 != None:
integer1 = integer1.next
if integer2 != None:
integer2 = integer2.next
return result;
first = create_linked_list([1, 2, 3]) #321
second = create_linked_list([1, 2]) #21
print("Sum:")
result = add_integers(first, second)
display(result)
 Explanation
For example: Let's take two integers, 9901 and 237. The output will be 10138.
First, the integers will be stored in inverted form in the linked lists. This will make addition easy. The last element of the linked list is the most significant digit. However, the addition will start from the heads of the two linked lists.
On every iteration, the code will add the current digits of the two lists and after adding a new node will be inserted with the resulting digit. This will be added at the tail of the resultlinked list. There's a need to maintain the carrying value at each step.
The iteration will terminate when both of the linked lists are exhausted. If any of the linked lists ends sooner, the addition will continue with the other linked list.
4. Build a deep copy of the given linked list where each node has two pointers: 'next' and 'arbitrary_pointer'.
This approach utilizes a map to track arbitrary nodes found by the primary list. You will have to create a deep copy of the primary linked list (say list_orig) in two passes.
 In the first pass, make a copy of the original linked list. When you are creating this copy, make use of the same values for data and arbitrary_pointer in the new list. Keep updating the map with entries with the key as the address to the old node, and the value will be the address of the new node.
 Once the copy gets created, do another take at the copied linked list and update the arbitrary pointers to the new address by using the map built in the first pass.
Binary Tree
5. Given the root to a binary tree where each node has an additional pointer called sibling (or next), connect the sibling pointer to the next node at the same level.
Code Part
 Language: C++
void populate_sibling_pointers(BinaryTreeNode* root) {
if (root == nullptr) {
return;
}
BinaryTreeNode* current = root;
BinaryTreeNode* last = root;
while (current != nullptr) {
if (current>left != nullptr) {
last>next = current>left;
last = current>left;
}
if (current>right != nullptr) {
last>next = current>right;
last = current>right;
}
last>next = nullptr;
current = current>next;
}
}
void reset_siblings(BinaryTreeNode* root) {
if (root == nullptr) return;
root>next = nullptr;
reset_siblings(root>left);
reset_siblings(root>right);
}
int main(int argc, char* argv[]) {
BinaryTreeNode* root = create_random_BST(15);
display_level_order(root);
cout << endl << "level_order_using_next";
level_order_using_next(root);
cout << endl;
reset_siblings(root);
populate_sibling_pointers(root);
level_order_using_next(root);
}
 Explanation
Initially, both the current and last are set as 'root,' while the current node is not null. Check for the left child in the current node. If it's there, then append this left node to the last and make it the last node. Now, check for the right child in the current node. If it's there, then append this right node to the last and make it the last node. Lastly, update the current node to the current's next node.
6. If you're given a Binary Tree, find out if it's a Binary Search Tree. In a binary search tree, each node's major value is smaller than the key value of all nodes in the right subtree, and greater than the major values of all nodes in the left subtree, i.e., L < N < R.
Code Part
 Language: C++
bool is_bst_rec(
BinaryTreeNode* root,
int min_value,
int max_value) {
if (root == nullptr) {
return true;
}
if (root>data < min_value 
root>data > max_value) {
return false;
}
return
is_bst_rec(root>left, min_value, root>data) &&
is_bst_rec(root>right, root>data, max_value);
}
bool is_bst(BinaryTreeNode* root) {
return
is_bst_rec(
root,
numeric_limits<int>::min(),
numeric_limits<int>::max());
}
void test_is_bst() {
BinaryTreeNode* root = create_random_BST(15);
BinaryTreeNode* root2 = create_BinaryTree(20);
root2>left = root;
root2>right = root;
display_level_order(root);
display_level_order(root2);
assert(is_bst(root));
assert(!is_bst(root2));
}
int main(int argc, char* argv[]) {
test_is_bst();
}
 Explanation
This code checks on each node where the minimum value of its right subtree is greater than the node’s data, and the maximum value of its left subtree is less than the node’s data.
Strings
7. If you're given a dictionary of words and an input string, find out whether the input string can be segmented into dictionary words.
 Algorithm
n = length of input string
for i = 0 to n  1
first_word = substring (input string from index [0, i] )
second_word = substring (input string from index [i + 1, n  1] )
if dictionary has first_word
if second_word is in dictionary OR second_word is of zero length, then return true
recursively call this method with second_word as input and return true if it can be segmented
 Explanation
The algorithm computes two strings from scratch in every iteration of the loop. Worst case scenario, there will be a recursive call of the second_word each time. This shoots the time complexity up to 2n.
You will see that you might be calculating the same substring multiple times, even if it doesn't exist in the dictionary. This can be fixed by memoization, where you can remember the substrings that have already been solved.
In order to achieve memoization, you will be able to store the second string in a new set each time. This will decrease time and memory complexities.
8. If you're given a string, discover all substrings that are palindromes.
Code Part
 Language: C++
int find_palindromes_in_sub_string(const string& input, int j, int k) {
int count = 0;
for (; j >= 0 && k < input.length(); j, ++k) {
if (input[j] != input[k]) {
break;
}
cout << input.substr(j, k  j + 1) << endl;
++count;
}
return count;
}
int find_all_palindrome_substrings(const string& input) {
int count = 0;
for (int i = 0; i < input.length(); ++i) {
count += find_palindromes_in_sub_string(input, i  1, i + 1);
count += find_palindromes_in_sub_string(input, i, i + 1);
}
return count;
}
int main() {
string str = "aabbbaa";
cout << "Total palindrome substrings: " << find_all_palindrome_substrings(str) << endl;
}
 Explanation
For every letter in the input string, expand to the left and right and check for even and odd length palindromes. Move to the next letter if you know a palindrome doesn't exist.
Expand one character to the left and right, and then, compare them. If both of the characters are equal, print out the palindrome substring.
9. If you're given an array of positive numbers and a positive number 'k', discover the maximum sum of any contiguous subarray of size 'k'.
Code Part
 Language: C++
int find_max_sum_sub_array(int A[], int n) {
if (n < 1) {
return 0;
}
int curr_max = A[0];
int global_max = A[0];
for (int i = 1; i < n; ++i) {
if (curr_max < 0) {
curr_max = A[i];
} else {
curr_max += A[i];
}
if (global_max < curr_max) {
global_max = curr_max;
}
}
return global_max;
}
int main() {
int v[] = {4, 2, 5, 1, 2, 3, 6, 5, 1};
cout << "Sum of largest subarray: " << find_max_sum_sub_array(v, sizeof(v) / sizeof(v[0])) << endl;
return 0;
}
 Explanation
Kadane's algorithm scans the entire array and each position, and find the maximum sum of the subarray ending there. This is achieved by keeping a curr_max for the current array index and a global_max.
10. If you're given an input string, find out if it makes a valid number or not. You can assume that white spaces are not present in the input.
Code Part
 Language: C++
enum STATE { START, INTEGER, DECIMAL, UNKNOWN, AFTER_DECIMAL};
STATE get_next_state(STATE current_state, char ch) {
switch(current_state) {
case START:
case INTEGER: {
if (ch == '.') {
return DECIMAL;
} else if (ch >= '0' && ch <= '9') {
return INTEGER;
} else {
return UNKNOWN;
}
break;
}
case DECIMAL:
if (ch >= '0' && ch <= '9') {
return AFTER_DECIMAL;
} else {
return UNKNOWN;
}
break;
case AFTER_DECIMAL:
if (ch >= '0' && ch <= '9') {
return AFTER_DECIMAL;
} else {
return UNKNOWN;
}
break;
case UNKNOWN:
return UNKNOWN;
}
return UNKNOWN;
}
bool is_number_valid(const string s) {
int i = 0;
if (s[i] == '+'  s[i] == '') {
i++;
}
STATE current_state = START;
while (s[i] != '\0') {
current_state = get_next_state(current_state, s[i]);
if (current_state == UNKNOWN) {
return false;
}
i++;
}
if (current_state == DECIMAL)
return false;
return true;
}
void test(const string s, bool expected) {
bool is_valid = is_number_valid(s);
if (is_valid) {
cout << s << " is valid." << endl;
} else {
cout << s << " is not valid." << endl;
}
}
int main(int argc, char* argv[]) {
test("4.325", true);
test("4.325a", false);
test("x4.325", false);
test("4.32.5", false);
test("4325", true);
test("1.", false);
test("1.1.", false);
test("1.1.1", false);
test("1.1.1.", false);
test("+1.1.", false);
test("+1.1", true);
test("1.1.", false);
test("1.1", true);
test("", true);
}
 Explanation
You can use the state machine to check if a number is valid or not. The initial state is 'Start'. Process each character to find the next state. The input string is not a valid number if you reach an UNKNOWN state at any point or if the number ends in a DECIMAL.
11. If you're given an NxN grid of characters and a dictionary, determine all words that can be made from the characters in the grid and are present in the dictionary. The word can begin and end at any character in the grid. The subsequent character has to be adjacent to the previous character in one of the directions, i.e., up, down, left, right or diagonal. The character at every position in the grid can be used just once while making a word.
Code Part
 Language: C++
class Boggle {
// code assumes that both dimensions of grid are same
public:
vector<vector<char>> grid;
unordered_set<string> dictionary;
vector<vector<bool>> state;
list<pair<int, int>> find_all_nbrs(int x, int y) {
list<pair<int, int>> nbrs;
int start_x = std::max(0, x  1);
int start_y = std::max(0, y  1);
int end_x = std::min((int)(grid.size()  1), x + 1);
int end_y = std::min((int)(grid.size()  1), y + 1);
for (int i = start_x; i <= end_x; ++i) {
for (int j = start_y; j <= end_y; ++j) {
if (state[i][j]) {
continue;
}
nbrs.push_back(pair<int, int>(i, j));
}
}
return nbrs;
}
void find_words_rec(int i, int j,string& current,unordered_set<string>& words) {
if (!current.empty() && dictionary.find(current) != dictionary.end()) {
words.insert(current);
}
// we can really speed up our algorithm if we have the prefix method available
// for our dictionary by using code like below
/*
if (!dictionary.is_prefix(current)) {
// if current word is not prefix of any word in dictionary
// we don't need to continue with search
return;
}
*/
list<pair<int, int>> nbrs = find_all_nbrs(i, j);
for (auto& pr : nbrs) {
current += grid[pr.first][pr.second];
state[pr.first][pr.second] = true;
find_words_rec(pr.first, pr.second, current, words);
current.resize(current.size()  1);
state[pr.first][pr.second] = false;
}
}
Boggle(const vector<vector<char>>& g, const unordered_set<string>& d) : grid(g), dictionary(d) {
state.resize(g.size());
for (vector<bool>& v : state) {
v.resize(g.back().size());
}
}
unordered_set<string> find_all_words(){
unordered_set<string> words;
string current_word;
for (int i = 0; i < grid.size(); ++i) {
for (int j = 0; j < grid.size(); ++j) {
find_words_rec(i, j, current_word, words);
}
}
return words;
}
};
int main(){
vector<vector<char>> grid = {{'c', 'a', 't'},
{'r', 'r', 'e'},
{'t', 'o', 'n'}};
unordered_set<string> dictionary = {"cat", "cater", "cartoon", "art", "toon", "moon", "eat", "ton"};
Boggle b(grid, dictionary);
unordered_set<string> words = b.find_all_words();
for (auto& s: words) {
cout << s << endl;
}
return 0;
}
 Explanation
It's a backtracking problem, and thus we have to start with one character in the grid and try to make as many words as possible, where the starting character is the selected character. This process will repeat the same for all the characters in the grid.
To find all the words beginning with a character, we utilize an algorithm very similar to a depthfirst search. Since every character from the grid can appear once in a word, we'll have to maintain a boolean matrix to indicate if the corresponding character in the grid is utilized for this word.
12. Find out the minimum spanning tree of a connected, undirected graph with weighted edges.
 Algorithm
Initialize the MST with an arbitrary vertex from the graph
Find the minimum weight edge from the constructed graph to the vertices not yet added in the graph
Add that edge and vertex to the MST
Repeat steps 23 until all the vertices have been added to the MST
 Explanation
Using Prim’s algorithm, we will find the minimum spanning tree of a graph. Prim's algorithm builds the tree one vertex at a time and thus starts from any arbitrary vertex. This method adds the minimum weight edge from the tree being constructed to a vertex from the remaining vertices at each step.
Miscellaneous
13. The Least Recently Used (LRU) is a known caching strategy. It defines the policy to remove elements from the cache to carve out space for new elements when the cache is full. It removes the least recently used items first.
Code Part
 Language: Python
class LRUCache:
def __init__(self, capacity):
self.capacity = capacity
self.cache = set()
self.cache_vals = LinkedList()
def set(self, value):
node = self.get(value)
if node == None:
if(self.cache_vals.size >= self.capacity):
self.cache_vals.insert_at_tail(value)
self.cache.add(value)
self.cache.remove(self.cache_vals.get_head().data)
self.cache_vals.remove_head()
else:
self.cache_vals.insert_at_tail(value)
self.cache.add(value)
else:
self.cache_vals.remove(value)
self.cache_vals.insert_at_tail(value)
def get(self, value):
if value not in self.cache:
return None
else:
i = self.cache_vals.get_head()
while i is not None:
if i.data == value:
return i
i = i.next
def printcache(self):
node = self.cache_vals.get_head()
while node != None :
print(str(node.data) + ", ")
node = node.next
cache1 = LRUCache(4)
cache1.set(10)
cache1.printcache()
cache1.set(15)
cache1.printcache()
cache1.set(20)
cache1.printcache()
cache1.set(25)
cache1.printcache()
cache1.set(30)
cache1.printcache()
cache1.set(20)
cache1.printcache()
 Explanation
To implement an LRU cache, we can use two data structures: a doubly linked list and a hashmap. A hashmap helps with the O(1) lookup of cached keys, and a doublylinked list helps in maintaining the eviction order and.
14. If you're given a list of intervals, merge all the overlapping intervals to build a list containing mutually exclusive intervals.
Code Part
 Language: C++
class Pair{
public:
int first, second;
Pair(int x, int y){
first = x;
second = y;
}
};
vector<Pair> merge_intervals(vector<Pair>& v) {
if(v.size() == 0) {
return v;
}
vector<Pair> result;
result.push_back(Pair(v[0].first, v[0].second));
for(int i = 1 ; i < v.size(); i++){
int x1 = v[i].first;
int y1 = v[i].second;
int x2 = result[result.size()  1].first;
int y2 = result[result.size()  1].second;
if(y2 >= x1){
result[result.size()  1].second = max(y1, y2);
}
else{
result.push_back(Pair(x1, y1));
}
}
return result;
}
int main() {
vector<Pair> v {
Pair(1, 5),
Pair(3, 7),
Pair(4, 6),
Pair(6, 8),
Pair(10, 12),
Pair(11, 15)
};
vector<Pair> result = merge_intervals(v);
for(int i = 0; i < result.size(); i++){
cout << "[" << result[i].first << ", " << result[i].second << "] ";
}
}
 Explanation
To solve this, we have made the following approach:
 Input intervals are given in a list, and that's why we will keep the merged intervals in the output list.
 For each interval in the input list:
 In case the input interval is overlapping with the last interval in the output list, then all we have to do is to merge these two intervals. After merging, we have to update the last interval of the output list with the merged interval.
 Otherwise, we have to add an input interval to the output list as an alternative scenario.
15. Search, or determine the position of a given key in a 2D matrix. Assume that all the rows and columns are sorted.
Code Part
 Language: C++
pair<int, int> search_in_matrix(vector<vector<int>> matrix, int value) {
int M = matrix.size(); //rows
int N = matrix[0].size(); // columns
// Let's start searching from top right.
// Alternatively, searching from bottom left
// i.e. matrix[M1][0] can also work.
int i = 0, j = N1;
while (i < M && j >= 0) {
if (matrix[i][j] == value) {
return pair<int, int>(i, j);
}
else if (value < matrix[i][j]) {
// search left
j;
}
else {
// search down.
++i;
}
}
return pair<int, int>(1, 1);
}
void verify_search(vector<vector<int>> matrix) {
for (int i = 0; i < matrix.size(); ++i) {
for (int j = 0; j < matrix[0].size(); ++j) {
cout << "Verifying at " << i << "," << j << ": " << matrix[i][j] << endl;
pair<int, int> value_loc = search_in_matrix(matrix, matrix[i][j]);
assert(value_loc.first == i);
assert(value_loc.second == j);
}
}
}
int main(int argc, char const *argv[])
{
vector<vector<int>> matrix = {
{1, 5, 45, 80, 81},
{6, 7, 48, 82, 83},
{20, 22, 49, 85, 86},
{21, 23, 50, 90, 92}
};
verify_search(matrix);
pair<int, int> value_loc;
value_loc = search_in_matrix(matrix, 100);
assert(value_loc.first == 1 && value_loc.second == 1);
return 0;
}
 Algorithm
We start from the upper right corner of the matrix, from where we first compare its value with the key. In case they are equal, then it means we have found the position of the key. We move one position to the left in case the key is smaller than the current element. Likewise, we move one position down in case the key is larger than the current element.
Most Common Adobe Coding Interview Questions
A number of 1 bit
A positive integer N is provided, and the applicant has to count the set bits in it.
 Approach
Before we begin, let's see an example: binary representation of 6 is 110 and has 2 set bits. How did we get this? It's pretty simple. First, loop through all bits in an integer. After looping, check if a bit is set. If a bit is set, then increment the set bit count.
Code: C++
import java.io.*;
class countSetBits {
/* Function to get no of set
bits in binary representation
of positive integer n */
static int countSetBits(int n)
{
int count = 0;
while (n > 0) {
count += n & 1;
n >>= 1;
}
return count;
}
// driver program
public static void main(String args[])
{
int i = 9;
System.out.println(countSetBits(i));
}
}
Generate Parentheses
An integer N is provided, representing the quantity of pairs of parentheses. You have to generate all combinations of the wellformed parenthesis.
 Approach
It's a simple approach where the i’th character can be referred to ‘{‘ if the count of ‘{‘ till i’th is less than n. Then the i'th character can be referred to ‘}’ if the count of ‘{‘ is greater than the count of ‘}’. This will continue till index i. If these cases are followed as per the criteria, then the subsequence (output) will always be balanced.
Code: C++
#include <bits/stdc++.h>
using namespace std;
vector<string> generateParenthesis(int n)
{
vector<string> two;
vector<string> ans;
if (n == 1) {
two.push_back("{}");
return two;
} // Returning vector if n==1
if (n == 2) {
two.push_back("{{}}");
two.push_back("{}{}");
return two;
} // Returning vector if n==2, as these are base cases
two = generateParenthesis(
n  1); // Recursively calling the function
// Assigning the previous values of vector into the
// present function
for (int i = 0; i < two.size(); i++) {
string buf = "{", bug = "{", bus = "{";
buf = buf + two[i] + "}";
bug = bug + "}" + two[i];
bus = two[i] + bus + "}";
ans.push_back(buf);
ans.push_back(bus);
ans.push_back(bug);
}
// Removing the duplicate as kind of this {}{} remains
// same in either way
ans.pop_back();
return ans;
}
int main()
{
vector<string>
ff; // Vector to store all the combinations
int n = 2;
ff = generateParenthesis(n); // Calling the function
for (int i = 0; i < ff.size(); ++i) {
cout << ff[i] << endl; // Print all the combinations
/* code */
}
}
Mirror Tree
A binary tree is provided, and you are asked to convert it into a mirror.
 Approach
 First, call the Mirror for the leftsubtree, that is Mirror(leftsubtree).
 Then, call the Mirror for the rightsubtree that is Mirror(rightsubtree).
 Now, swap both left and right subtrees using
temp = leftsubtree
leftsubtree = rightsubtree
rightsubtree = temp
Code: C++
#include<bits/stdc++.h>
using namespace std;
struct Node
{
int data;
struct Node* left;
struct Node* right;
};
struct Node* newNode(int data)
{
struct Node* node = (struct Node*)
malloc(sizeof(struct Node));
node>data = data;
node>left = NULL;
node>right = NULL;
return(node);
}
void mirror(struct Node* node)
{
if (node == NULL)
return;
else
{
struct Node* temp;
mirror(node>left);
mirror(node>right);
temp = node>left;
node>left = node>right;
node>right = temp;
}
}
void inOrder(struct Node* node)
{
if (node == NULL)
return;
inOrder(node>left);
cout << node>data << " ";
inOrder(node>right);
}
// Driver Code
int main()
{
struct Node *root = newNode(1);
root>left = newNode(2);
root>right = newNode(3);
root>left>left = newNode(4);
root>left>right = newNode(5);
cout << "Inorder traversal of the constructed"
<< " tree is" << endl;
inOrder(root);
mirror(root);
cout << "\nInorder traversal of the mirror tree"
<< " is \n";
inOrder(root);
return 0;
}
InOrder Traversal
A binary tree is given, and inorder traversal is required.
 Approach
 First, you need to find the index of the maximum element in the given array. This maximum element must be the root of the Binary Tree.
 Now, store this maximum value found in step 1 in a new tree node ‘root’ after creation.
 Call buildTree for elements before the maximum element. After calling, make this built tree as the left subtree of ‘root’.
 Call buildTree for elements after the maximum element. After calling, make this built tree the right subtree of ‘root’.
 Return ‘root’ as output.
Code: C++
#include <bits/stdc++.h>
using namespace std;
class node
{
public:
int data;
node* left;
node* right;
};
int max(int inorder[], int strt, int end);
node* newNode(int data);
node* buildTree (int inorder[], int start, int end)
{
if (start > end)
return NULL;
int i = max (inorder, start, end);
node *root = newNode(inorder[i]);
if (start == end)
return root;
root>left = buildTree (inorder, start, i  1);
root>right = buildTree (inorder, i + 1, end);
return root;
}
int max (int arr[], int strt, int end)
{
int i, max = arr[strt], maxind = strt;
for(i = strt + 1; i <= end; i++)
{
if(arr[i] > max)
{
max = arr[i];
maxind = i;
}
}
return maxind;
}
node* newNode (int data)
{
node* Node = new node();
Node>data = data;
Node>left = NULL;
Node>right = NULL;
return Node;
}
void printInorder (node* node)
{
if (node == NULL)
return;
printInorder (node>left);
cout<<node>data<<" ";
printInorder (node>right);
}
int main()
{
int inorder[] = {5, 10, 40, 30, 28};
int len = sizeof(inorder)/sizeof(inorder[0]);
node *root = buildTree(inorder, 0, len  1);
cout << "Inorder traversal of the constructed tree is \n";
printInorder(root);
return 0;
}
Print the Pattern
An integer N is given, and a print of the desired pattern is required.
Code: C++
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n = 5, i, j, num = 1, gap;
gap = n  1;
for ( j = 1 ; j <= n ; j++ )
{
num = j;
for ( i = 1 ; i <= gap ; i++ )
cout << " ";
gap ;
for ( i = 1 ; i <= j ; i++ )
{
cout << num;
num++;
}
num;
num;
for ( i = 1 ; i < j ; i++)
{
cout << num;
num;
}
cout << "\n";
}
return 0;
}
Check if the given numbers are Fibonacci numbers.
A number N is given. The test is to check if N is a part of the Fibonacci series.
 Approach
A number 'n' is called a Fibonacci if one or both of (5*n2 + 4) or (5*n2 – 4) is a perfect square. We will use this formula to check if the number is in the Fibonacci series or not.
Code: C++
#include <iostream>
#include <math.h>
using namespace std;
bool isPerfectSquare(int x)
{
int s = sqrt(x);
return (s*s == x);
}
bool isFibonacci(int n)
{
return isPerfectSquare(5*n*n + 4) 
isPerfectSquare(5*n*n  4);
}
int main()
{
for (int i = 1; i <= 10; i++)
isFibonacci(i)? cout << i << " is a Fibonacci Number \n":
cout << i << " is a not Fibonacci Number \n" ;
return 0;
}
Tips for Adobe Interview Preparation
Before the Interview
 In addition to updating your résumé and LinkedIn page, if feasible, incorporate deliverables and statistics as genuine examples of your achievements.
 If you're applying for a job, be aware that whatever information you provide on your resume could be used against you.
 As a solid practice, spend approximately two minutes discussing each item on your resume and connecting your successes and prior experiences to their essential values: real, remarkable, inventive, and engaged.
For the Interview
 It's best not to attempt to memorize particular questions.
 In order to remain on top of the game and try new things, companies of this scale frequently change the questions they ask. You'll be asked a variety of questions throughout the interview process, and the specifics will depend on the team and recruiting manager.
Learn .Net Programming With Simplilearn
Accelerate your chances of clearing the Adobe interview questions by learning valuable skills. Signup for our PGP in Fullstack Web Development in collaboration with Caltech CTME. In just a few months, you'll learn modern coding techniques with bootcamplevel intensity and gain all you need to be a fullstack technologist. Apply now and start learning!