L&T Technology Services Interview Questions · 2026

L&T Technology Services Interview Questions (2026)

A candidate who documented their L&T Technology Services loop on GeeksforGeeks described a first round that felt more like a competitive exam than a tech screen: 90 multiple choice questions split evenly across logical reasoning, quantitative aptitude, and domain knowledge, plus two coding problems, all in one sitting. Fifty seven people cleared that round and moved on to interviews (GeeksforGeeks, LTTS interview experience). That structure, a heavy online assessment followed by a technical round and then HR, shows up again and again in candidate reports, whether the role is software engineering, embedded systems, or one of LTTS's core engineering R&D domains like automotive or industrial products.

L&T Technology Services is the engineering R&D services arm spun out of Larsen & Toubro, and that lineage shows up in the interview itself. It is not a pure software shop. A software engineer candidate might get asked about OOP and SQL in the same loop where a mechanical design engineer gets asked about transformer sizing and IEC standard compliance, and an embedded engineer gets asked to write UART code on a whiteboard (Indeed, L&T Technology Services interview reviews). Candidates rate the overall difficulty as moderate to difficult depending on role, and most report the whole process wrapping up inside two to four weeks.

This page covers around 50 questions pulled from candidate-reported rounds: the online assessment, coding and data structures, core CS fundamentals (OOP, Java, C++), SQL, system design basics, embedded systems and firmware, domain engineering, and the resume-based and HR rounds. Where reports were thin on specifics, we say so instead of inventing detail.

~50Questions
3-4Rounds
90 MCQ + 2 codingOA Format
2-4 weeksTypical Timeline

Online assessment and aptitude

The first hurdle at LTTS is usually a single long online test rather than a series of shorter ones. Candidate reports describe 30 logical reasoning questions, 30 quantitative aptitude questions, and 30 domain-specific questions, sitting alongside two coding problems, all under a time limit. It rewards speed and accuracy more than depth on any one topic.

Easy questions

15

Triage before you solve. Skim each section for roughly thirty seconds and flag the questions you can answer in under a minute, those are worth locking in first because a wrong guess on a quant problem costs you the same as a wrong guess on a domain question, but the domain questions tend to eat more time if you second guess yourself.

On a 90-question paper split three ways, budget your time per section rather than per question. If quant is your weak spot, decide up front you'll spend two minutes max per question there and move on, coming back only if time remains. Leaving five domain questions blank because you burned twenty minutes on two hard quant problems is the single most common way candidates torpedo an otherwise strong score.

Standard verbal and non-verbal reasoning: syllogisms, seating arrangements, blood relations, coding-decoding, series completion, and direction sense problems. None of it is specific to engineering, it is the same pool most Indian IT and ER&D recruiters draw from for entry to mid level hiring.

The trap is treating these as throwaway warm-up questions. A seating arrangement puzzle with five or six constraints can eat ten minutes if you don't sketch it out systematically on scratch paper the moment you read it, rather than trying to hold all the constraints in your head while reading the answer choices.

Percentages, ratios, time and work, time and distance, simple and compound interest, permutations and combinations, and basic probability cover the large majority of what shows up. These are the classic topics from Indian campus placement aptitude tests, and if you've prepared for any other large IT services company's hiring process, you've already seen most of this.

Speed matters more than elegance here. Memorize the shortcut formulas for time-and-work and percentage-change problems rather than deriving them from first principles under time pressure. That's a two second lookup versus a ninety second derivation, multiplied across thirty questions.

Two sum is the canonical warm-up because the naive answer and the good answer differ by an entire order of complexity. Brute force checks every pair, O(n squared). The better approach walks the array once, and for each element checks whether the complement, target minus the current value, has already been seen, using a hash map keyed by value to index.

python
def two_sum(nums, target):
  seen = {}
  for i, n in enumerate(nums):
    complement = target - n
    if complement in seen:
      return [seen[complement], i]
    seen[n] = i
  return []

What separates a pass from a strong pass here is not getting to O(n), most candidates know that pattern, it's correctly handling duplicate values and explaining why you check the map before inserting the current element rather than after.

Two passes over the string solve this cleanly. First pass builds a frequency count of every character. Second pass walks the string in order again and returns the first character whose count is exactly one. Order matters here, you need the first non-repeating character in the original string's order, not sorted by frequency.

python
def first_unique_char(s):
  counts = {}
  for ch in s:
    counts[ch] = counts.get(ch, 0) + 1
  for ch in s:
    if counts[ch] == 1:
      return ch
  return None

A candidate who tries to solve this in one pass usually overcomplicates it with an ordered structure they don't need. Two clean O(n) passes beats one clever but buggy pass, and interviewers notice when you say that out loud rather than forcing elegance you can't quite land.

Encapsulation bundles data and the methods operating on it, hiding internal state behind a public interface, think of a BankAccount class exposing deposit and withdraw but never letting external code touch the balance field directly. Abstraction hides implementation complexity behind a simpler interface, a Database class with a query method that hides connection pooling and retry logic from the caller. Inheritance lets a class reuse and extend another's behavior, a SavingsAccount extending Account and adding interest calculation. Polymorphism lets code call the same method name on different types and get type-appropriate behavior, calling calculateInterest on a list of mixed SavingsAccount and FixedDepositAccount objects and getting each one's own logic.

Overloading is having multiple methods with the same name but different parameter lists in the same class, resolved at compile time based on the arguments you pass. Overriding is a subclass providing its own implementation of a method already defined in its parent class, resolved at runtime based on the actual object type, which is what makes polymorphism work.

java
class Shape {
  double area() { return 0; }
}
class Circle extends Shape {
  double radius;
  @Override
  double area() { return Math.PI * radius * radius; } // overriding
}
class Calculator {
  int add(int a, int b) { return a + b; }
  double add(double a, double b) { return a + b; } // overloading
}

A LIMIT/OFFSET approach after sorting descending works in most databases, and it's the cleanest answer when duplicates aren't a concern. If duplicate salaries need to be treated as a single rank, DENSE_RANK is the more correct tool.

sql
SELECT DISTINCT salary
FROM Employee
ORDER BY salary DESC
LIMIT 1 OFFSET 1;

-- handles ties correctly using dense rank
SELECT salary FROM (
 SELECT salary, DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
 FROM Employee
) ranked
WHERE rnk = 2;

INNER JOIN returns only rows that have a match in both tables. LEFT JOIN returns every row from the left table, filling in NULLs for columns from the right table where no match exists. FULL OUTER JOIN returns every row from both tables, matched where possible, NULL-filled on whichever side lacks a match.

sql
SELECT e.name, d.dept_name
FROM Employee e
LEFT JOIN Department d ON e.dept_id = d.id;
-- every employee appears, even ones with no matching department

The compiler is free to cache a normal variable's value in a register and reuse that cached value across multiple reads, assuming nothing else changes it between accesses. volatile tells the compiler that assumption doesn't hold, the value can change outside the normal flow of the program, an interrupt handler, a memory-mapped hardware register, so it must re-read the actual memory location every single time, no caching, no reordering.

c
volatile uint8_t *status_register = (uint8_t *)0x4000;

while (!(*status_register & 0x01)) {
  // without volatile, compiler might read this once and loop forever,
  // since it looks like nothing in this loop body changes the value
}

I2C uses two shared wires, clock and data, for all devices on the bus, addressing each device by a unique ID over that shared line, which keeps wiring simple but limits speed and requires careful bus arbitration when multiple devices might want to talk. SPI uses separate clock, data-in, data-out lines plus a dedicated chip-select line per device, which needs more pins as you add devices but runs faster and has no addressing overhead since chip select alone determines which device is being talked to.

Choose I2C when pin count is tight and speed isn't critical, connecting several low-speed sensors on a board with limited GPIO. Choose SPI when you need higher throughput and have the pins to spare, driving a display or flash memory where I2C's speed ceiling would be a real bottleneck.

IEC standards exist so equipment designed and manufactured in different countries, by different vendors, can be relied on to meet the same safety and performance baseline, which matters enormously for LTTS's business since much of its engineering R&D work serves clients whose products ship globally and must clear certification in multiple regulatory jurisdictions.

IEC 60950 (now largely superseded by IEC 62368-1) covers safety for information technology and audio-visual equipment. IEC 61010 covers safety requirements for electrical measurement and laboratory equipment. Knowing the exact clause numbers matters less in an interview than being able to explain why a design engineer needs to think about certification requirements from the earliest design stage rather than retrofitting compliance after the fact, since some failures, inadequate creepage and clearance distances on a PCB, for example, require a physical redesign to fix.

This question is doing double duty: it's checking whether you can explain your own work clearly to someone who wasn't there, and it's setting up every follow-up question for the rest of the technical round, since interviewers almost always probe deeper into whatever project you highlight. Pick the project where you can defend every technical decision under a follow-up, not necessarily the most impressive-sounding one on paper.

Structure the walkthrough around the problem, your specific contribution, and one decision you'd make differently in hindsight. That last part matters more than candidates expect, it signals you can evaluate your own past work critically rather than just narrating a highlight reel, and it usually heads off a harder follow-up before it gets asked.

This shows up in candidate-reported HR rounds at LTTS as a straightforward, unadorned question, and the honest answer works better than a rehearsed one. Interviewers are checking for two things: whether your stated direction is plausible given the role you're interviewing for, and whether you've thought about your own trajectory at all rather than treating the job as a placeholder.

A strong answer connects a realistic next step, deeper technical ownership, a specific domain you want to grow into, team leadership, to something the role you're interviewing for could plausibly develop. Vague ambition ("I want to be successful") reads worse than a specific, modest goal that shows you've actually thought about the next few years rather than treating the question as a formality to get past.

Location preference comes up directly in LTTS HR rounds, and it's a logistics question with real hiring consequences, not a trick. LTTS operates delivery centers across multiple Indian cities plus global engineering centers, and role assignment often depends on which center actually has the open headcount for your specific skill set.

Answer honestly rather than saying yes to everything to seem agreeable. If you have a genuine constraint, a location you can't relocate to for family reasons, say so plainly, since backing out after an offer over an undisclosed constraint costs you more credibility than a straightforward answer up front would have.

Medium questions

23

Go back to your core branch fundamentals rather than trying to guess LTTS-specific trivia. If you're an ECE or CS graduate, that means digital logic, computer networks basics, operating systems concepts, and data structures at the definitional level, what's a semaphore, what's the difference between TCP and UDP, what's a hash collision. If you're mechanical or electrical, it means machine design basics, thermodynamics, or circuit theory fundamentals depending on your specialization.

The domain section tests whether your degree stuck, not whether you've memorized an LTTS-specific question bank. Treat it like a refresher of your final year coursework rather than a new topic to learn from scratch.

Candidate reports describe basic to intermediate problems, array manipulation and tree traversal being two topics that come up, run on an autograded platform like HackerRank with a fixed time window. These are not competitive programming problems requiring an unusual algorithmic insight, they are closer to "can this person write correct, working code under a clock" checks.

Practice writing complete functions from an empty editor rather than filling in a partial solution, since the online round typically gives you a blank canvas and a function signature rather than a scaffolded template. Getting the syntax right without an IDE's autocomplete is its own skill worth rehearsing separately from the algorithm itself.

Reports don't detail LTTS's exact cutoff logic, and it likely varies by hiring cycle and role volume, so treat any specific claim about section-wise cutoffs as unverified. What's consistent across reports is that the test acts as a volume filter before the technical round, moving a large applicant pool down to a manageable interview slate, in one documented case, 57 candidates advanced.

The safest approach is to not leave any section badly underrepresented. Even if quant isn't your strength, answering enough of it to clear a plausible per-section floor protects you from being screened out on a technicality rather than genuine ability.

A tree is height balanced if, for every node, the height difference between its left and right subtrees is at most one, and both subtrees are themselves balanced. The naive approach recomputes height from scratch at every node, which is O(n squared) in the worst case because you're re-walking subtrees repeatedly.

python
def is_balanced(root):
  def check(node):
    if not node:
      return 0
    left = check(node.left)
    if left == -1:
      return -1
    right = check(node.right)
    if right == -1:
      return -1
    if abs(left - right) > 1:
      return -1
    return max(left, right) + 1

  return check(root) != -1

The trick worth naming out loud is using a sentinel value, -1, to signal "already found an imbalance" and short circuit the rest of the recursion, instead of computing height and balance as two separate passes. That gets you to a single O(n) traversal.

Floyd's cycle detection, the tortoise and hare approach, is the expected answer. Run two pointers through the list, one advancing one node at a time, the other advancing two. If there's a cycle, the faster pointer eventually laps the slower one and they meet inside the loop. If there's no cycle, the faster pointer reaches the end first.

python
def has_cycle(head):
  slow = fast = head
  while fast and fast.next:
    slow = slow.next
    fast = fast.next.next
    if slow == fast:
      return True
  return False

The follow-up worth being ready for is finding the actual start of the cycle, not just detecting one. Once slow and fast meet, resetting one pointer to the head and advancing both one step at a time until they meet again lands exactly on the cycle's entry node, a fact that follows from the math behind Floyd's algorithm rather than something you'd guess intuitively.

If one array has enough trailing empty slots to hold both, walk from the back of both arrays simultaneously, placing the larger of the two current elements into the last open slot and decrementing the appropriate pointer. Working backward avoids overwriting values in the first array before you've read them, which is the bug candidates hit when they try to merge from the front in place.

python
def merge(nums1, m, nums2, n):
  i, j, k = m - 1, n - 1, m + n - 1
  while j >= 0:
    if i >= 0 and nums1[i] > nums2[j]:
      nums1[k] = nums1[i]
      i -= 1
    else:
      nums1[k] = nums2[j]
      j -= 1
    k -= 1

A virtual function in C++ tells the compiler to resolve the call at runtime through a vtable lookup based on the object's actual type, rather than at compile time based on the pointer or reference type. Without virtual, calling a base class pointer's method always invokes the base class version even if the pointer actually points at a derived object, static binding.

cpp
class Animal {
public:
  virtual void speak() { std::cout << "..."; }
};
class Dog : public Animal {
public:
  void speak() override { std::cout << "Woof"; }
};

Animal* a = new Dog();
a->speak(); // prints "Woof" only because speak() is virtual

Java methods are virtual by default, every instance method except those marked final or static resolves dynamically, because Java was designed around the assumption that polymorphism should be the default behavior. C++ inherited its object model from a design philosophy of paying only for what you use, a non-virtual call is cheaper, a direct function call rather than a vtable indirection, so it makes virtual opt-in instead.

Undefined behavior in the strict sense, but in practice, only the base class destructor runs. Any resources the derived class allocated, heap memory, file handles, get leaked because the derived destructor that would have cleaned them up never executes.

cpp
class Base {
public:
  ~Base() { std::cout << "Base destroyedn"; }
};
class Derived : public Base {
public:
  ~Derived() { std::cout << "Derived destroyedn"; }
  int* data = new int[100];
};

Base* b = new Derived();
delete b; // only "Base destroyed" prints, Derived's destructor never runs, leak

The rule every C++ codebase should follow: if a class is meant to be a base class for polymorphic use, give it a virtual destructor even if it does nothing else. It costs one vtable entry and saves you from a genuinely nasty class of leak.

An abstract class can hold both fully implemented methods and abstract ones a subclass must implement, plus instance state. An interface, in languages that have both concepts distinctly, Java before 8 for instance, only declares method signatures with no implementation and no state at all. A class can extend only one abstract class but implement multiple interfaces.

Choose an abstract class when subclasses genuinely share common implementation you don't want repeated. Choose an interface when you're defining a contract multiple unrelated classes should satisfy, a Flyable interface that both Bird and Airplane implement despite sharing nothing else. Modern Java's default methods on interfaces have blurred this line somewhat, but the intent distinction still holds.

A memory leak happens when heap memory allocated with new or malloc is never freed, and every reference to it goes out of scope, so the program can no longer reach it to free it either, but the memory stays reserved for the life of the process. Do this repeatedly in a long-running service and memory usage climbs until the process gets killed by the OS or the machine runs out.

In practice you'd reach for a tool rather than manual code inspection first, Valgrind on Linux is the classic answer, it runs your program and reports every allocation that was never freed by exit, along with the call stack that made the allocation. On Windows, the CRT debug heap or Visual Studio's built-in leak detection does something similar. The habit that prevents most leaks in modern C++ is simply not using raw new and delete directly, wrapping ownership in smart pointers, unique_ptr and shared_ptr, so the destructor handles cleanup automatically even when an exception unwinds the stack early.

Normalization organizes tables to eliminate redundant data and update anomalies, splitting a table so each fact is stored in exactly one place. First normal form removes repeating groups, second removes partial dependencies on a composite key, third removes transitive dependencies, a non-key column depending on another non-key column instead of directly on the primary key.

Denormalization deliberately reintroduces some redundancy to avoid expensive joins on read-heavy paths. A reporting dashboard querying millions of rows might store a precomputed customer_name alongside an order row instead of joining to a Customer table every single time, trading some update complexity and storage for read speed. The right call depends entirely on the read-to-write ratio of the specific table, not a blanket rule either way.

A clustered index determines the physical order rows are stored on disk, so a table can have only one, it is the table's actual storage order, not a separate structure pointing at it. A non-clustered index is a separate structure holding the indexed column's values plus a pointer back to the actual row, and a table can have many of these.

Looking up a value through a non-clustered index costs an extra hop, find the entry in the index, then follow its pointer to the actual row, unless the index itself covers every column the query needs, called a covering index, in which case that extra hop is skipped entirely.

This needs a correlated subquery, because "average" here means average within that specific employee's department, not the whole table's average. The subquery re-runs once per outer row, filtered to that row's department.

sql
SELECT e.name, e.salary, e.dept_id
FROM Employee e
WHERE e.salary > (
 SELECT AVG(salary)
 FROM Employee e2
 WHERE e2.dept_id = e.dept_id
);

A window function version avoids the correlated subquery's row-by-row re-execution and tends to perform better on large tables, worth mentioning as the production-grade alternative even if the correlated subquery is the more intuitive first answer.

Vertical scaling means adding more resources, CPU, RAM, to a single machine. Horizontal scaling means adding more machines and distributing load across them. Vertical scaling is simpler, no distributed systems complexity, no need to handle partial failures across nodes, but it hits a hard ceiling, there's a maximum size machine you can buy, and a single point of failure remains.

Horizontal scaling has no theoretical ceiling and survives individual node failure, but it introduces real complexity, load balancing, data consistency across nodes, network calls where there used to be in-process calls. Most systems start vertical because it's cheap and simple, and move horizontal once a single machine's ceiling becomes the actual bottleneck, not before.

A semaphore is a counting synchronization primitive that lets a limited number of threads or tasks access a resource concurrently, decrementing on acquire and incrementing on release, blocking when the count hits zero. A binary semaphore restricts that count to 0 or 1, functioning like a simple lock, but conceptually it's still signaling, one task can post to a semaphore that a different task then waits on.

A mutex looks similar but carries an important extra rule: ownership. Only the task that locked a mutex can unlock it, and most RTOS implementations enforce that. A binary semaphore has no notion of ownership, any task can post to it regardless of which task last waited on it, which makes it the right tool for signaling between two different tasks, an ISR signaling a waiting task that data is ready, for instance, but the wrong tool for protecting a shared resource where ownership matters.

UART transmission at the register level is fundamentally a busy-wait or interrupt-driven check of a transmit-buffer-empty flag before writing the next byte, since the hardware transmit buffer can only hold one byte (or a small FIFO) at a time and writing to it before it's empty either blocks or corrupts the in-flight byte.

c
void uart_send_byte(uint8_t data) {
  while (!(UART_STATUS_REG & TX_EMPTY_FLAG)) {
    // busy-wait until the transmit buffer is ready
  }
  UART_DATA_REG = data;
}

void uart_send_string(const char *str) {
  while (*str) {
    uart_send_byte(*str++);
  }
}

The interrupt-driven version replaces the busy-wait with an ISR triggered on the transmit-empty flag, pulling the next byte from a ring buffer, which frees the CPU to do other work instead of blocking, the standard upgrade path once a design moves past a bring-up prototype.

Preemptive scheduling lets the scheduler interrupt a running task at any point, typically on a timer tick or when a higher priority task becomes ready, and switch context to another task without that task's cooperation. Cooperative scheduling requires each task to voluntarily yield control, either by finishing or explicitly calling a yield function, and a task that never yields blocks every other task indefinitely.

Real-time systems with hard deadlines almost always need preemptive scheduling, because a low priority task that misbehaves shouldn't be able to starve a time-critical one just by refusing to yield. Cooperative scheduling is simpler to reason about, no need for reentrant code or careful locking since context switches only happen at points you control, but it puts the correctness burden entirely on every task author remembering to yield promptly.

A bootloader is the small piece of firmware that runs first on power-on, before the main application, and is responsible for initializing minimal hardware and then either jumping to the main application or, in update scenarios, checking for and applying a new firmware image before handing off control.

If the bootloader itself gets corrupted, most devices become unrecoverable through normal firmware update channels, since the bootloader is exactly the code responsible for accepting and validating a new firmware image in the first place. This is why production hardware designs typically protect the bootloader region with write protection or a dual-bank scheme, a golden, unmodifiable fallback bootloader alongside the updatable one, specifically to survive a failed update without needing a hardware programmer to recover the device.

The core inputs are the load's real power demand in kVA, factoring in power factor since apparent power, not just real power, determines the current the transformer must handle, plus a margin for future load growth so the transformer isn't running at its rated ceiling from day one. Voltage ratio, primary and secondary voltage levels, has to match the source and load requirements exactly, and impedance, expressed as a percentage, affects both fault current levels downstream and voltage regulation under load.

Thermal considerations matter as much as the electrical sizing itself. Ambient temperature at the installation site, ventilation or cooling method, oil-filled versus dry-type, and duty cycle, continuous load versus intermittent peaks, all affect how much margin above the calculated minimum kVA rating you should build in. Undersizing shows up as accelerated insulation aging and eventual failure well before its rated lifespan.

Start from the actual load profile, total watt-hours the connected equipment draws over the required backup duration, not just its peak wattage, since a battery bank sized only for peak load without accounting for duration will run out mid-outage. Divide required watt-hours by the battery's usable voltage and apply a depth-of-discharge derating, most battery chemistries shouldn't be fully discharged repeatedly without shortening their cycle life significantly.

Temperature and aging both eat into a battery's effective capacity versus its nameplate rating, so a sizing calculation that comes out exactly at the load requirement with zero margin is undersized in practice. A reasonable design adds headroom for capacity fade over the battery's expected service life and for real-world temperatures that rarely match the manufacturer's rated test conditions.

A static load is constant or changes so slowly the structure can be treated as being in equilibrium at every instant, a shelf holding a fixed weight. A dynamic load varies over time, impact, vibration, cyclic loading from a rotating part, and its effect on a structure depends not just on peak magnitude but on frequency and duration of application.

Material selection for dynamic loading has to account for fatigue, a material can fail at stress levels well below its static yield strength if that stress is applied cyclically enough times, the classic S-N curve relationship. A design that passes a static load calculation with a comfortable safety margin can still fail in the field after months of vibration if fatigue wasn't part of the original analysis, which is a real and recurring gap between a component that survives a bench test and one that survives its actual service life.

The interviewer is checking two things at once: whether you can voice a disagreement constructively, and whether you know when to let go of a fight you've lost and execute anyway. A story where you just deferred silently signals you don't push back at all. A story where you kept escalating past a clear decision signals you don't know when to stop.

The strongest version of this answer includes the specific reasoning you brought to the disagreement, evidence, not just an opinion, how the conversation actually resolved, and what happened afterward, especially if the decision went against you and you still executed it well. That last part is what separates a candidate who's genuinely collaborative from one who's just telling the interviewer what they think they want to hear.

A generic answer here, "I want to grow my career", falls flat against a company that has a specific identity: an engineering R&D services arm of a much larger industrial conglomerate, working across automotive, industrial products, medical devices, and process industries rather than being a pure software shop. Naming that distinction and connecting it to something concrete about your own background, prior exposure to hardware-adjacent engineering, interest in a specific domain LTTS serves, shows you've actually looked past the company name.

Avoid answers that would apply equally well to any large employer. If your genuine reason is compensation or convenience of location, that's a legitimate reason to want a job, but it's not what this question is asking, and an interviewer can tell the difference between a candidate who researched the company and one reciting a template.

Hard questions

7

In-place rotation for a square matrix breaks into two simpler operations chained together: transpose the matrix, swap element (i,j) with (j,i) across the diagonal, then reverse each row. Doing both in sequence produces a 90 degree clockwise rotation without allocating a second matrix.

python
def rotate(matrix):
  n = len(matrix)
  for i in range(n):
    for j in range(i + 1, n):
      matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
  for row in matrix:
    row.reverse()

Candidates who haven't seen this decomposition before tend to try tracking four-way swaps directly, which works but is error prone to code correctly under interview pressure. Transpose-then-reverse is the version worth memorizing because it reduces a fiddly geometric problem to two operations you already trust.

The diamond problem happens when a class inherits from two classes that both inherit from a common base, so the derived class ends up with two separate copies of the base class's members, ambiguous which one a reference to a base member resolves to.

cpp
class A { public: int x; };
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {}; // virtual inheritance: only one copy of A

D d;
d.x = 5; // unambiguous, because A is shared, not duplicated

C++'s answer is virtual inheritance, declaring the shared base as virtual in both intermediate classes so the most-derived class gets exactly one shared instance of it instead of two. Java sidesteps the whole problem by disallowing multiple class inheritance entirely, only single inheritance for classes, which is part of why interfaces exist as a separate concept there.

Deadlock happens when two or more threads each hold a resource the other needs and neither will release what it's holding, so both wait forever. The classic case: thread A locks resource 1 then tries to lock resource 2, while thread B has already locked resource 2 and is trying to lock resource 1. Neither can proceed.

java
// Deadlock risk: threads acquire locks in different orders
synchronized(lock1) {
  synchronized(lock2) { /* work */ } // Thread A
}
synchronized(lock2) {
  synchronized(lock1) { /* work */ } // Thread B, opposite order
}

The standard prevention is enforcing a consistent lock acquisition order across every thread in the system, always lock1 before lock2, everywhere, no exceptions. Timeouts on lock attempts, backing off and retrying if a lock can't be acquired within a bounded window, are a defensive fallback for cases where a strict global order is impractical to enforce.

Common algorithms include round robin, cycling through servers in order, least connections, sending traffic to whichever server currently has the fewest active connections, and weighted variants of either that account for servers with different capacity. The right choice depends on whether requests are roughly uniform in cost, round robin is fine, or highly variable, least connections handles that better.

A load balancer detects a down server through health checks, periodic pings or lightweight status endpoint calls on a fixed interval, and stops routing new traffic to any server that fails enough consecutive checks. In-flight requests to that server typically fail and get retried against a healthy server, which is why idempotent request handling on the backend matters, a retried request shouldn't double-charge a customer or double-insert a record.

Start by ruling out the usual intermittent-bug suspects: uninitialized stack variables whose garbage values happen to differ between bench and field power-on conditions, race conditions between an ISR and the main loop that only manifest under specific timing that your bench setup doesn't trigger, and stack overflow that corrupts adjacent memory only under a particular call depth or interrupt nesting pattern that field conditions hit more often.

Practical tooling matters more than theory here. A watchdog timer that logs the last known program counter or a small crash-dump routine writing critical state to non-volatile memory right before a reset gives you forensic evidence from the field even without a debugger attached. Stack canaries, a known sentinel value written just past the stack's expected bound, checked periodically, catch stack overflow before it silently corrupts something else and turns into a much harder to diagnose crash three function calls later.

Priority inversion happens when a high priority task is blocked waiting on a resource held by a low priority task, and a medium priority task, unrelated to that resource, preempts the low priority one, effectively letting a medium priority task delay a high priority task indefinitely, inverting the intended priority order.

Priority inheritance fixes this by temporarily boosting the low priority task holding the contested resource up to the priority of the highest priority task waiting on it, for as long as it holds that resource. That guarantees the medium priority task can't preempt it in the meantime, since the resource holder now outranks it, letting the low priority task finish and release the resource quickly, after which its priority drops back down. This exact bug, undetected priority inversion, caused watchdog resets on the Mars Pathfinder mission and is a genuinely famous case study in embedded systems courses for exactly that reason.

This question filters out candidates who only have success stories rehearsed, since every real engineering career includes projects that slipped, broke, or got cancelled, and an interviewer who's been doing this a while can usually tell when a "failure" story has been sanded down to have no actual stakes.

Pick a real failure with a real consequence, missed deadline, production bug that reached customers, a design that had to be reworked late in the cycle, and be specific about your own role in what went wrong rather than framing it as something that happened to you. The learning you name at the end should be something you've demonstrably applied since, a process change, a technical habit, not a generic platitude about communication being important. Specificity is what makes this answer land instead of sounding like every other behavioral answer an interviewer hears that day.

Real-time scenario questions

5

An LRU cache needs O(1) get and put, which rules out a plain array or list scanned linearly for recency. The standard answer combines a hash map for O(1) key lookup with a doubly linked list that tracks recency order, most recently used at the head, least recently used at the tail. On every access, move that node to the head. When capacity is exceeded, evict from the tail and remove its entry from the map too.

python
class Node:
  def __init__(self, key, value):
    self.key, self.value = key, value
    self.prev = self.next = None

class LRUCache:
  def __init__(self, capacity):
    self.cap = capacity
    self.map = {}
    self.head = Node(0, 0)
    self.tail = Node(0, 0)
    self.head.next, self.tail.prev = self.tail, self.head

  def _remove(self, node):
    node.prev.next, node.next.prev = node.next, node.prev

  def _add_front(self, node):
    node.next, node.prev = self.head.next, self.head
    self.head.next.prev = node
    self.head.next = node

  def get(self, key):
    if key not in self.map:
      return -1
    node = self.map[key]
    self._remove(node)
    self._add_front(node)
    return node.value

  def put(self, key, value):
    if key in self.map:
      self._remove(self.map[key])
    node = Node(key, value)
    self.map[key] = node
    self._add_front(node)
    if len(self.map) > self.cap:
      lru = self.tail.prev
      self._remove(lru)
      del self.map[lru.key]

The part interviewers actually probe on is whether you can explain why a plain hash map alone isn't enough, you need the ordering structure too, and Python's own OrderedDict or a language's built-in linked-hash-map exists precisely because this pattern is common enough to warrant a standard library shortcut.

The core problem is mapping a long URL to a short, unique key and reversing that lookup fast. A common approach: assign each new URL an auto-incrementing ID, then encode that ID into a short base-62 string, using digits, lowercase, and uppercase letters, which gives you a compact, collision-free key without needing to check for uniqueness after the fact.

Storage is a simple key-value mapping, short key to long URL, which is exactly the access pattern a key-value store or an indexed relational table handles well. The scaling considerations worth naming: a cache layer in front of the database for the popular subset of links that get hit repeatedly, and a read-heavy access pattern overall since redirects vastly outnumber new URL creation. Custom aliases and expiry are reasonable follow-up features to mention, not core requirements.

Start with the power path itself: confirm every component's voltage and current rating has margin above the actual operating condition, not just the nominal one, since transient spikes during startup or load changes routinely exceed steady-state values. Check that decoupling capacitors are placed close to every IC's power pins in the schematic's net structure, and that ground return paths are explicit rather than assumed.

Beyond the power path, verify protection: reverse polarity protection if the input connector could plausibly be mis-wired in the field, overcurrent protection sized to trip before a downstream fault damages the board, and ESD protection on any externally accessible connector. A schematic review is fundamentally about imagining every way a real user or a real fault condition could stress the circuit beyond its intended operating envelope, not just confirming the happy path works on paper.

Sorting the whole array gets you there in O(n log n), and it's a defensible first answer, but the stronger one is quickselect, a partition-based approach borrowed from quicksort that finds the kth largest in average O(n) time by only ever recursing into the partition that could contain the answer, discarding the other half entirely instead of sorting it.

python
import random

def find_kth_largest(nums, k):
  target = len(nums) - k

  def partition(left, right):
    pivot = nums[right]
    i = left
    for j in range(left, right):
      if nums[j] <= pivot:
        nums[i], nums[j] = nums[j], nums[i]
        i += 1
    nums[i], nums[right] = nums[right], nums[i]
    return i

  left, right = 0, len(nums) - 1
  while True:
    pivot_index = partition(left, right)
    if pivot_index == target:
      return nums[pivot_index]
    elif pivot_index < target:
      left = pivot_index + 1
    else:
      right = pivot_index - 1

Worth mentioning unprompted: quickselect degrades to O(n squared) on an adversarial input if the pivot choice is naive, always picking the last element, for example. A random pivot or median-of-three selection defends against that, and naming the failure mode shows you understand why the average case claim holds rather than just reciting it.

Individually-passing, integration-failing is almost always a tolerance stack-up or interface assumption problem rather than a defect in any single part. Each component can be within its own drawing tolerance and still produce an assembly that doesn't fit or function correctly, because tolerances compound across a chain of mating parts, and nobody validated the cumulative worst case, only each part's individual spec.

The systematic approach is a tolerance stack-up analysis across the actual assembly chain, worst-case or statistical, RSS, depending on how conservative the application needs to be, identifying which dimension in the chain contributes the most variance to the failure mode you're seeing. Root cause almost always traces back to either an interface that was designed and toleranced independently by two different engineers without a shared reference datum, or an assumption baked into one part's tolerance that quietly depended on another part being at its nominal dimension rather than its worst-case one.

How to prepare for an L&T Technology Services interview

Start with the online assessment, since it is the widest funnel and the easiest round to lose points on through pure time management rather than lack of knowledge. Time yourself on a mixed aptitude set before the real thing, thirty logical, thirty quant, thirty domain, plus two coding problems, all under one clock, and get comfortable with the discipline of skipping a question you're stuck on rather than burning five minutes defending against a sunk cost.

For the technical round, resist the urge to prep a generic DSA sheet and stop there. LTTS technical interviews pull from your actual resume more heavily than a pure product-company loop tends to, so be ready to defend every project listed, not just the flashy one at the top, and refresh core OOP and SQL fundamentals even if your recent work has been mostly scripting or configuration rather than fresh design work. If you're interviewing for an embedded or hardware-adjacent role, the domain questions get specific fast, RTOS scheduling, protocol details, sizing calculations, so a general software prep sheet alone will leave real gaps.

In LastRoundAI mock interview sessions with candidates preparing for ER&D-style roles like LTTS's, the resume deep-dive trips people up more often than the coding round does, mostly because candidates over-prepare algorithms and under-prepare a tight, honest explanation of their own recent work. Practicing that walkthrough out loud, with someone pushing back on your design choices, closes that gap faster than another round of LeetCode.

Get the reps in before the real thing

Reading through fifty questions is not the same as fielding a follow-up you didn't expect, out loud, under a clock. LastRoundAI's mock interview mode runs live technical and behavioral rounds with real-time follow-up questions in your browser, and the free plan includes 15 credits a month that reset monthly rather than piling up unused. Starter is $19/mo if a handful of sessions isn't enough runway before your actual interview date.

Once your answers hold up under pressure, the slower part of the process is usually just getting your resume in front of enough ER&D and engineering roles that actually match what you've built. Auto-Apply queues tailored applications for your review, 10 a month on the free plan, up to 400 a month on the Ultimate plan, and nothing goes out until you approve it.

Questions about either product go to contact@lastroundai.com.

How this list was built

Worth being straight about where these questions come from, because plenty of pages in this category are not. The set was compiled from a research pass across official documentation, vendor release notes, published engineering writing and public discussion of hiring processes, then cross-checked against the current version of each technology so nothing here describes behaviour that has since changed.

What that means in practice: these are the questions the material supports as reasonable and current for this role, not a transcript of any one company's loop. We have not sat in on your interview and we are not going to claim we have. Treat the list as well-sourced preparation rather than a leaked question bank, and expect your panel to phrase things their own way.

If you spot something out of date, tell us at contact@lastroundai.com and we will fix it.

Frequently asked questions

How many rounds does the L&T Technology Services interview have?

Most L&T Technology Services processes run an online aptitude and technical assessment, then one or two technical interviews, then an HR round. Lateral hiring often drops the aptitude test and goes straight to technical. The exact shape varies by campus drive versus off-campus, so confirm with your recruiter rather than assuming.

Is the L&T Technology Services aptitude test hard to clear?

It is more about pace than difficulty. The quantitative and logical sections are standard campus-placement material, but the time per question is tight, so accuracy under time pressure is what actually filters people out. Practising with a clock matters more than learning new topics.

What should freshers focus on for a L&T Technology Services interview?

One programming language you can write confidently on paper, core CS fundamentals (OOP, DBMS, operating systems, networks), and a project you can explain end to end. Freshers who can defend their own project in detail consistently do better than those who list five projects shallowly.

Does L&T Technology Services ask coding questions in the interview?

Usually yes, though at a moderate level rather than competitive-programming difficulty. Expect array and string manipulation, basic recursion and SQL. Being able to explain your approach out loud carries real weight, because the interviewer is assessing trainability as much as correctness.

Leave a Reply

Your email address will not be published. Required fields are marked *