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.

Post Graduate Program: Full Stack Web Development

in Collaboration with Caltech CTMEEnroll Now
Post Graduate Program: Full Stack Web Development

About Adobe

Founded in 1982, Adobe is an American computer software company headquartered in San Jose, California. The company is behind pioneering the paper-to-digital 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

  • Acrobat
  • Photoshop
  • Illustrator
  • Adobe XD
  • Adobe Express
  • InDesign
  • Lightroom
  • Dreamweaver
  • Fresco
  • Adobe Scan
  • Adobe Connect
  • Adobe Capture
  • Aero
  • Spark Video
  • Adobe Analytics
  • Adobe Target
  • Journey Optimizer
  • Real-time CDP
  • Advertising Cloud
  • Campaign
  • Intelligent Services
  • Marketo Engage
  • Connect
  • PostScript
  • ColdFusion
  • RoboHelp
  • Dynamic Streaming
  • FrameMaker
  • Media Server

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 off-campus recruitment drives, Adobe also employs freshers. The following are the major procedures that are followed in the recruiting of Adobe freshers.

  1. Campus visit or application via a career portal or recruiting agency
  2. CV evaluation
  3. Written exam for Adobe's entry-level hiring. This entails creating pseudo-code and occasionally essay-style questions
  4. Multiple technical interview rounds
  5. 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.

  1. Resume evaluation for Adobe position
  2. Telephone conversation (pre-technical round)
  3. Online coding assignment
  4. Adobe's technical interviews 
  5. 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.

  1. 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.
  2. There should be no educational backlogs on the part of the applicants.
  3. Candidates with a solid understanding of computer science, problem-solving 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 off-campus 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 65-question online technical exam once you pass the phone screen.

  1. Aptitude and Logic (45 questions, 45 minutes): To see how well you can reason quantitatively and logically.
  2. Technical and Coding (15-20 questions, 75-120 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.

New Course: Full Stack Development for Beginners

Learn Git Command, Angular, NodeJS, Maven & MoreEnroll Now
New Course: Full Stack Development for Beginners
  • Onsite Interview

Final-round 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 technology-related interviews:

  1. Interview on System Design 
  2. Interview on Object-Oriented 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

Full Stack Web Developer Course

To become an expert in MEAN StackView Course
Full Stack Web Developer Course

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 result-linked 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.

  1. 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.
  2. 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

Free Course: Programming Fundamentals

Learn the Basics of ProgrammingEnroll Now
Free Course: Programming Fundamentals

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.

Full Stack Java Developer Course

In Partnership with HIRIST and HackerEarthEXPLORE COURSE
Full Stack Java Developer Course

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 depth-first 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 2-3 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 doubly-linked list helps in maintaining the eviction order and. 

FREE Java Certification Training

Learn A-Z of Java like never beforeEnroll Now
FREE Java Certification Training

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:

  1. Input intervals are given in a list, and that's why we will keep the merged intervals in the output list.
  2. 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[M-1][0] can also work.

int i = 0, j = N-1;

  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.

Adobe_IQ_1.

  • 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 well-formed parenthesis.

adobe_IQ_2

  • 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.

adobe_IQ_3.

  • Approach
  1. First, call the Mirror for the left-subtree, that is Mirror(left-subtree). 
  2. Then, call the Mirror for the right-subtree that is Mirror(right-subtree). 
  3. Now, swap both left and right subtrees using- 

         temp = left-subtree

         left-subtree = right-subtree

         right-subtree = 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; 

}

In-Order Traversal

A binary tree is given, and in-order traversal is required.

adobe_IQ_4

  • Approach
  1. 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. 
  2. Now, store this maximum value found in step 1 in a new tree node ‘root’ after creation. 
  3. Call buildTree for elements before the maximum element. After calling, make this built tree as the left subtree of ‘root’. 
  4. Call buildTree for elements after the maximum element.  After calling, make this built tree the right subtree of ‘root’. 
  5. 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.

adobe_IQ_5.

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.

adobe_IQ_6.

  • 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. Sign-up for our PGP in Full-stack Web Development in collaboration with Caltech CTME. In just a few months, you'll learn modern coding techniques with bootcamp-level intensity and gain all you need to be a full-stack technologist. Apply now and start learning!

About the Author

SimplilearnSimplilearn

Simplilearn is one of the world’s leading providers of online training for Digital Marketing, Cloud Computing, Project Management, Data Science, IT, Software Development, and many other emerging technologies.

View More
  • Disclaimer
  • PMP, PMI, PMBOK, CAPM, PgMP, PfMP, ACP, PBA, RMP, SP, and OPM3 are registered marks of the Project Management Institute, Inc.