Published: 11 Feb 2025 | Reading Time: 7 min read
Tata Consultancy Services (TCS) is among the most sought-after companies for freshers and experienced professionals alike, and TCS Ninja is the hiring process that piques the interest of both. The process consists of coding challenges with precise expectations to evaluate a candidate's level of skill. These TCS Ninja coding questions aim to assess problem-solving skills, technical proficiencies, and logical thinking in general.
Understanding the types of coding questions that TCS Ninja usually asks, as well as how to approach these questions and some best practices on how to cruise through the tests, can be crucial while preparing for this competitive interview. This article looks into the various aspects of coding questions for TCS Ninja interviews, right from those targeted to freshers and experienced candidates to answer multiple-choice questions (MCQs).
TCS Ninja is an entry-level hiring program by Tata Consultancy Services (TCS) for fresh graduates. It tests candidates' aptitude, programming, and communication skills to select them for software roles. The exam includes quantitative aptitude, logical reasoning, verbal ability, and coding. Candidates who perform well may be shortlisted for interviews assessing technical knowledge and problem-solving skills. Preparing for TCS Ninja requires a good understanding of C, Java, or Python and strong analytical skills. It is a great opportunity for students looking to start their careers in the IT industry with one of India's top companies.
To register for TCS Ninja Recruitment, follow these steps:
Following these steps, you can successfully register for the TCS Ninja recruitment drive and begin preparing.
TCS Digital, an initiative by Tata Consultancy Services (TCS), focuses on supporting businesses in their digital transformation journey while also recruiting skilled digital talent. It provides various services, including digital labs, innovative software solutions, and enhanced customer experience offerings.
To register for TCS Digital Recruitment, follow these steps:
Go to the official TCS NextStep website: https://nextstep.tcs.com
The choice between TCS Ninja and TCS Digital depends on your skills, experience, and career goals. Here's a comparison to help you decide:
The TCS Ninja Coding Round is a crucial part of the selection process, assessing problem-solving and programming skills. Here's what you need to know:
| Category | Details |
|---|---|
| Number of Questions & Difficulty Level | Typically 3 or 4 coding questions. Difficulty level: Hard. Covers topics like arrays, strings, recursion, sorting, and basic data structures. |
| Time Duration | 90 minutes, depending on the exam pattern for that year. |
| Allowed Programming Languages | Candidates can code in any of the following languages: C, C++, Java, Python, Perl |
| Question Types | Basic Algorithmic Problems (e.g., Fibonacci series, prime numbers, factorial). String Manipulation (e.g., reversing a string, checking palindromes). Array-Based Problems (e.g., finding missing numbers, sum of elements). Mathematical & Logical Puzzles (e.g., pattern-based problems). |
The TCS Ninja recruitment process is divided into two parts: Cognitive Skills and Programming Skills. Below is the detailed syllabus:
Candidates can write code in any of the following programming languages:
Being a fresher, the competitive TCS Ninja interview process may seem daunting. However, a well-planned approach to TCS Ninja coding questions can work wonders for your success. The interview for freshers typically tests fundamental programming skills and logical reasoning.
The most common coding questions for TCS Ninja interviews for freshers tend to focus on the following:
Fresh graduates entering the TCS Ninja program often face a mix of straightforward and moderately challenging coding problems. These problems typically test basic programming concepts, logical reasoning, and algorithmic thinking.
Classic string reversal is a traditional problem that will help you in string manipulation and understand some of the basic algorithms. In Python, the slicing function makes it easy and efficient to perform such a reversal by using a step value of -1. This will allow the slice to traverse in reverse, starting from the end of the string.
For example, consider the string "hello". Using slicing in Python, we can reverse it with the following code:
def reverse_string(s):
# Slicing technique to reverse a string in Python
return s[::-1]
# Example
input_string = "hello"
reversed_string = reverse_string(input_string)
print("Reversed String:", reversed_string)
Output:
Reversed String: olleh
=== Code Execution Successful ===
Here, s[::-1] slices the string, starting from the end and stepping backwards, producing a reversed version of the string. This approach is concise and performs well in Python.
In C++, reversing a string typically involves manually swapping characters from both ends of the string towards the centre. This iterative approach ensures that the string is reversed in place without using additional space for a new string.
#include <iostream>
#include <string>
using namespace std;
string reverse_string(string s) {
int n = s.length();
for (int i = 0; i < n / 2; ++i) {
swap(s[i], s[n - i - 1]);
}
return s;
}
int main() {
string input = "hello";
string reversed = reverse_string(input);
cout << "Reversed String: " << reversed << endl;
return 0;
}
Output:
Reversed String: olleh
=== Code Execution Successful ===
The loop iterates up to half the length of the string, swapping characters from both ends, effectively reversing the string.
Concepts Covered: String manipulation, loops, slicing techniques
The maximum-finding problem has an effortless appeal. It requires the same approach of iterating through the array while maintaining a reference to the largest element that has already been seen. It is quite easy to implement with a for loop that compares each element with the current maximum in Python.
Assuming we have an array consisting of [1, 5, 3, 9, 2], we start with the assumption that the first element is the maximum. The most recent maximum will be updated each time the current maximum encounters a number larger than itself.
def find_maximum(arr):
max_element = arr[0]
for num in arr:
if num > max_element:
max_element = num
return max_element
arr = [1, 5, 3, 9, 2]
print("Maximum Element:", find_maximum(arr))
Output:
Maximum Element: 9
=== Code Execution Successful ===
The function first takes the very first element of the array and treats it as the max_element. It then traverses through the elements in the array, assigning to max_element the value of the larger number it encounters. The algorithm runs in O(n), where n is the number of elements present in the array.
#include <iostream>
#include <vector>
using namespace std;
int find_maximum(vector<int>& arr) {
int max_element = arr[0];
for (int i = 1; i < arr.size(); ++i) {
if (arr[i] > max_element) {
max_element = arr[i];
}
}
return max_element;
}
int main() {
vector<int> arr = {1, 5, 3, 9, 2};
cout << "Maximum Element: " << find_maximum(arr) << endl;
return 0;
}
Output:
Maximum Element: 9
=== Code Execution Successful ===
Concepts Covered: Array traversal, loops, conditionals
The famous problem of parentheses balancing in a string is an implementation of the stack data structure. The approach is to push opening parentheses into the stack as they occur but popping them each time a closing parenthesis comes. If a closing parenthesis doesn't correspond to the closing of the most recent opening parenthesis, the string is not well-formed.
For instance, let us consider "(())". We will proceed through the string while, on getting the character (, we commit it to the stack. When we get a character closing parenthesis ), we check the opening parenthesis on top of the stack. Conclusively, on completion of reading the string, if the stack is now empty, it means that there are balanced parentheses.
def is_balanced(s):
stack = []
for char in s:
if char == '(':
stack.append('(')
elif char == ')':
if not stack or stack[-1] != '(':
return False
stack.pop()
return len(stack) == 0
input_string = "(())"
print("Balanced Parentheses:", is_balanced(input_string))
Output:
Balanced Parentheses: True
=== Code Execution Successful ===
This solution is implemented using a stack to make sure that every opening parenthesis has a related closing parenthesis. The stack is empty at the end which means that the parentheses are balanced.
#include <iostream>
#include <stack>
#include <string>
using namespace std;
bool is_balanced(string s) {
stack<char> stack;
for (char c : s) {
if (c == '(') {
stack.push('(');
} else if (c == ')') {
if (stack.empty() || stack.top() != '(') {
return false;
}
stack.pop();
}
}
return stack.empty();
}
int main() {
string input = "(())";
cout << "Balanced Parentheses: " << (is_balanced(input) ? "Yes" : "No") << endl;
return 0;
}
Output:
Balanced Parentheses: Yes
=== Code Execution Successful ===
This solution checks for balanced parentheses in O(n) time complexity, where n is the length of the string.
Concepts Covered: Stack data structure, string traversal
To check if the number is prime means to check if it is divisible by any number other than 1 and itself. A prime number can be nicely divisible by 1 or itself. The algorithm used to check for primality is iterating in the range of 2 to the square root of the number. This is because any factor larger than the square root would have already been found as a smaller factor.
For example, to check if 17 is prime, we iterate from 2 to the square root of 17 (approximately 4.12). Since no numbers divide 17 evenly, it is prime. On the other hand, 18 is divisible by 2 and 3, so it is not prime.
import math
def is_prime(num):
if num <= 1:
return False
for i in range(2, int(math.sqrt(num)) + 1):
if num % i == 0:
return False
return True
print("Is 17 prime?", is_prime(17))
print("Is 18 prime?", is_prime(18))
Output:
Is 17 prime? True
Is 18 prime? False
=== Code Execution Successful ===
In the code, we employ a loop starting from 2 to the square root of the number to check for divisibility. If it finds a divisor amidst those iterations, it returns a False; if, upon completion, there are no factors, it returns a True.
#include <iostream>
#include <cmath>
using namespace std;
bool is_prime(int num) {
if (num <= 1) return false;
for (int i = 2; i <= sqrt(num); ++i) {
if (num % i == 0) {
return false;
}
}
return true;
}
int main() {
cout << "Is 17 prime? " << (is_prime(17) ? "Yes" : "No") << endl;
cout << "Is 18 prime? " << (is_prime(18) ? "Yes" : "No") << endl;
return 0;
}
Output:
Is 17 prime? Yes
Is 18 prime? No
=== Code Execution Successful ===
Since we are only checking for divisibility against numbers up to the square root of n, the time complexity is O(√n) which is much better than O(n) and gives time for checking divisibility for any number.
Concepts Covered: Loops, conditionals, mathematical optimization
# Function to calculate the Nth Fibonacci number
def fibonacci(n):
if n <= 0:
return "Input should be a positive integer."
elif n == 1:
return 0
elif n == 2:
return 1
else:
a, b = 0, 1
for _ in range(2, n):
a, b = b, a + b
return b
# Main function to take user input and compute Fibonacci number
if __name__ == "__main__":
try:
# Get the Nth Fibonacci number from user input
n = int(input("Enter the value of N: "))
if n <= 0:
print("Please enter a positive integer.")
else:
# Call fibonacci function and display the result
result = fibonacci(n)
print(f"The {n}th Fibonacci number is: {result}")
except ValueError:
print("Please enter a valid integer for N.")
Output:
Enter the value of N: 10
The 10th Fibonacci number is: 34
=== Code Execution Successful ===
This Python code calculates the Nth Fibonacci number by prompting the user to enter an integer value for n. It uses an iterative approach to compute the Fibonacci sequence up to the specified index. If the input is valid, it outputs the Nth Fibonacci number; otherwise, it displays an error message. For example, when the user inputs 10, the output will be "The 10th Fibonacci number is: 34."
Concepts Covered: Recursion, iteration, command line arguments, input validation
For experienced candidates, the expectations are higher. The focus shifts to much more complex and sophisticated problems that require a deeper understanding of programming concepts, data structures, and algorithms. For candidates with experience, TCS coding questions may include:
Problem Statement: Find the length of the longest increasing subsequence given an integer array. The subsequence does not have to be contiguous itself, but its elements should account for an increasing order.
In this way, we will use Dynamic Programming to solve the problem. The idea is to create a DP table where each entry dp[i] denotes the longest increasing subsequence that ends at index i. We will check, for each element of the array, whether it is extending any of those sequences that end before it by comparing it to the previous elements.
def longest_increasing_subsequence(arr):
if not arr:
return 0
# Initialize the dp array where each element is 1
dp = [1] * len(arr)
for i in range(1, len(arr)):
for j in range(i):
if arr[i] > arr[j]:
dp[i] = max(dp[i], dp[j] + 1)
# The length of the longest increasing subsequence is the maximum value in dp
return max(dp)
# Example
arr = [10, 22, 9, 33, 21, 50, 41, 60, 80]
print("Length of Longest Increasing Subsequence:", longest_increasing_subsequence(arr))
Output:
Length of Longest Increasing Subsequence: 6
=== Code Execution Successful ===
The longest increasing subsequence for the input array [10, 22, 9, 33, 21, 50, 41, 60, 80] would be: [10, 22, 33, 50, 60, 80] and length would be 6.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int longest_increasing_subsequence(vector<int>& arr) {
if (arr.empty()) return 0;
vector<int> dp(arr.size(), 1);
for (int i = 1; i < arr.size(); ++i) {
for (int j = 0; j < i; ++j) {
if (arr[i] > arr[j]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
return *max_element(dp.begin(), dp.end());
}
int main() {
vector<int> arr = {10, 22, 9, 33, 21, 50, 41, 60, 80};
cout << "Length of Longest Increasing Subsequence: " << longest_increasing_subsequence(arr) << endl;
return 0;
}
Output:
Length of Longest Increasing Subsequence: 6
=== Code Execution Successful ===
The C++ implementation is pretty similar to the Python version. The dp array will store the length of the longest increasing subsequence that ends at every index. The nested loops compare each element with the previous elements and thus update the dp array accordingly. The result will be the maximum element in the dp array obtained, which will be the LIS length.
Concepts Covered: Dynamic Programming, array manipulation, optimization
Implement an LRU Cache that supports the following operations:
get(key): returns the value associated with a key, provided the key exists in the cache; else -1put(key, value): insert or update the value for a key. If adding the value exceeds the cache size, then remove the least (recently) used onesApproach: To build an LRU cache efficiently, you can either use an OrderedDict in Python or use a combination of a doubly linked list and a hashmap. The former keeps track of the order in which data was inserted, and the latter allows for efficient removal of the least recently used item. The hashmap allows for the fast searching of keys for the get and put operations.
from collections import OrderedDict
class LRUCache:
def __init__(self, capacity: int):
self.cache = OrderedDict()
self.capacity = capacity
def get(self, key: int) -> int:
if key in self.cache:
self.cache.move_to_end(key)
return self.cache[key]
return -1
def put(self, key: int, value: int) -> None:
if key in self.cache:
self.cache.move_to_end(key)
elif len(self.cache) == self.capacity:
self.cache.popitem(last=False) # Remove least recently used item
self.cache[key] = value
# Example Usage
lru = LRUCache(2)
lru.put(1, 1)
lru.put(2, 2)
print(lru.get(1)) # Returns 1
lru.put(3, 3) # Evicts key 2
print(lru.get(2)) # Returns -1 (not found)
lru.put(4, 4) # Evicts key 1
print(lru.get(1)) # Returns -1 (not found)
print(lru.get(3)) # Returns 3
print(lru.get(4)) # Returns 4
The LRU Cache is created with an initial capacity. An OrderedDict is used extensively to store key-value pairs, keeping the order of their insertion. Whenever we access a key using get, if the key exists, it gets moved to the last position in the OrderedDict so that it maintains that it is the most recently used element. Whenever a new key-value pair is added, and the capacity is breached, the least recently used item is removed from the OrderedDict by using the method popitem(last=False).
After inserting keys (1,1), (2,2), and (3,3), the cache looks like this: {1:1, 2:2, 3:3}. After put(4,4), key 1 is evicted because it is the least recently used.
Output:
1
-1
-1
3
4
=== Code Execution Successful ===
#include <iostream>
#include <unordered_map>
using namespace std;
// Doubly Linked List Node
struct Node {
int key, value;
Node* prev;
Node* next;
};
class LRUCache {
private:
int capacity;
unordered_map<int, Node*> cache;
Node* head;
Node* tail;
void remove(Node* node) {
node->prev->next = node->next;
node->next->prev = node->prev;
}
void insert(Node* node) {
node->next = head->next;
node->prev = head;
head->next->prev = node;
head->next = node;
}
public:
LRUCache(int capacity) {
this->capacity = capacity;
head = new Node();
tail = new Node();
head->next = tail;
tail->prev = head;
}
int get(int key) {
if (cache.find(key) == cache.end()) {
return -1;
}
Node* node = cache[key];
remove(node);
insert(node);
return node->value;
}
void put(int key, int value) {
if (cache.find(key) != cache.end()) {
Node* node = cache[key];
node->value = value;
remove(node);
insert(node);
} else {
Node* node = new Node();
node->key = key;
node->value = value;
cache[key] = node;
insert(node);
if (cache.size() > capacity) {
Node* lru = tail->prev;
remove(lru);
cache.erase(lru->key);
delete lru;
}
}
}
};
// Example
int main() {
LRUCache cache(3);
cache.put(1, 1);
cache.put(2, 2);
cache.put(3, 3);
cout << cache.get(2) << endl; // 2
cache.put(4, 4);
cout << cache.get(1) << endl; // -1
cout << cache.get(3) << endl; // 3
cout << cache.get(4) << endl; // 4
return 0;
}
Output:
2
-1
3
4
=== Code Execution Successful ===
This solution operates in O(1) time for both get and put operations, making it highly efficient.
Concepts Covered: Data structures (doubly linked list, hashmap), cache implementation, O(1) operations
The Lowest Common Ancestor (LCA) of two nodes in a binary tree is the deepest node that is an ancestor of both nodes. This problem is widely used to test your understanding of recursion, tree traversal, and working with hierarchical data structures. The simplest approach is to use recursion to traverse the tree and check for the presence of the two nodes. If the root of a subtree is equal to one of the target nodes, then that root itself is the LCA. If the two nodes are found in different subtrees, the root of the current tree is the LCA.
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def findLCA(root, n1, n2):
# Base case: If the root is None or the root is one of the nodes
if root is None or root.value == n1 or root.value == n2:
return root
# Recur for the left and right subtrees
left = findLCA(root.left, n1, n2)
right = findLCA(root.right, n1, n2)
# If both left and right subtrees return non-None values, root is LCA
if left and right:
return root
# Otherwise, return the non-None value
return left if left else right
# Example usage
root = TreeNode(3)
root.left = TreeNode(5)
root.right = TreeNode(1)
root.left.left = TreeNode(6)
root.left.right = TreeNode(2)
root.right.left = TreeNode(0)
root.right.right = TreeNode(8)
root.left.right.left = TreeNode(7)
root.left.right.right = TreeNode(4)
n1, n2 = 5, 1
lca = findLCA(root, n1, n2)
if lca:
print(f"LCA of {n1} and {n2} is {lca.value}")
else:
print("LCA not found")
Output:
LCA of 5 and 1 is 3
=== Code Execution Successful ===
Concepts Covered: Binary trees, recursion, tree traversal, hierarchical data structures
Cracking the TCS Ninja coding questions requires a combination of knowledge, practice, and time management skills. By focusing on foundational programming concepts, solving a wide range of problems, and preparing for both coding challenges and MCQs, you can significantly improve your chances of success. Whether you are a fresher or an experienced candidate, mastering the skills required for the TCS Ninja coding interview will set you on the path to securing a position with one of the most prestigious companies in the world.
Learn more about coding by enrolling into the Intensive 3.0 Program at https://www.ccbp.in/intensive
Python, Java, and C++ are highly recommended due to their versatility and efficiency.
The difficulty ranges from basic to moderate for freshers and moderate to advanced for experienced candidates.
Yes, TCS Ninja coding questions in Python are commonly asked due to the language's simplicity and effectiveness for problem-solving.
This depends on the specific year's recruitment guidelines. Always confirm the rules before attempting.
Typically, the coding assessment lasts 60-90 minutes, depending on the format.
NxtWave provides comprehensive IT training programs to help students and professionals prepare for technical interviews and build successful careers in technology.
Contact Information:
Course Offerings:
Additional Resources: