0% found this document useful (0 votes)
9 views74 pages

My Document - PDF Dsa Report

This document is a report on 'Data Structure and Applications AAT' (BCS304) conducted by students at BMS Institute of Technology and Management for the academic year 2024-2025. It includes various programming problems and solutions related to data structures such as arrays, stacks, queues, linked lists, trees, and graphs. The report has been certified by the course coordinator as meeting the academic requirements for the B.E Degree.

Uploaded by

1by23ai040
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views74 pages

My Document - PDF Dsa Report

This document is a report on 'Data Structure and Applications AAT' (BCS304) conducted by students at BMS Institute of Technology and Management for the academic year 2024-2025. It includes various programming problems and solutions related to data structures such as arrays, stacks, queues, linked lists, trees, and graphs. The report has been certified by the course coordinator as meeting the academic requirements for the B.E Degree.

Uploaded by

1by23ai040
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 74

VISVESVARAYA TECHNOLOGICAL UNIVERSITY

BELAGAVI - 590 018, KARNATAKA

A Report on
“Data Structure and Applications AAT”
(BCS304)
in
ARTIFICIAL INTELLIGENCE AND MACHINE LEARNING
By
Mr.Darshan
Miss. Honey Pawar
Hemant Hampannavar USN: 1by23ai040
1BY24AI405

Mrs. Shruthi S
Associate Professor
Department of AIML, BMSIT&M.

ಬಿ.ಎಂ.ಎಸ್. ತಂತ್ರಿ ಕ ಮತ್ತು ವ್ಯ ವ್ಸ್ಥಾ ಪನಾ ಮಹಾವಿದ್ಯಯ ಲಯ


BMS Institute of Technology and Management
(An Autonomous Institution Affiliated to VTU, Belagavi)
Avalahalli, Doddaballapur Main Road, Bengaluru – 560119

2024-2025

VISVESVARAYA TECHNOLOGICAL UNIVERSITY


1
BELAGAVI – 590 018, KARNATAKA

ಬಿ.ಎಂ.ಎಸ್. ತಂತ್ರಿ ಕ ಮತ್ತು ವ್ಯ ವ್ಸ್ಥಾ ಪನಾ ಮಹಾವಿದ್ಯಯ ಲಯ


BMS Institute of Technology and Management
(An Autonomous Institution Affiliated to VTU, Belagavi)
Avalahalli, Doddaballapur Main Road, Bengaluru – 560119

CERTIFICATE

This is to certify that the AAT “Data structure and Applications” is the work carried out by Miss.
Honey Hemant Hampannavar (1BY24AI405) of Data Structure and Applications Theory
(BCS304) of the BMSIT&M during the year 2024-25. The report has been approved as it satisfies
the academic requirements in respect AAT work for the B.E Degree.

Signature of the Course Cordinator

Marks Distribution
1.
2.
3
Total

2
Programs
Sl.No Topic Question Page
Numbers
1 Array 1. First unique character in string 4
2. Combination sum 6
3. Permutations 8
4. Single number II 10
5. Median of two sorted arrays 12
2 Stacks 1.Evaluate reverse polish notation 14
2.Min stack 16
3.basic Calculator 18
4.Decode string 21
5.Longest valid parenthesis 24
3 Queue 1. First unique character in string 26
2. Combination sum 27
3.Permutations 30
4.Single number II 31
5.Median of two sorted arrays 34
4 Linked 1.Remove Nth node from end of list 36
List 2.Add two numbers 38
3.Swap nodes in pairs 41
4.Reverse the nodes 45
5.All O’one data structure 47
5 Trees 1.Binary tree inorder traversal 50
2.Unique binary search trees 52
3. Flatten binary tree to linked list 53
4. Binary tree level order traversed 56
4.serialize and deserialize a binary tree 59
6 Graphs 1.Course schedule 62
2.Redundant connection 64
3.Satisfiability of equality equation 67
4.Flower planting with no adjacent 69
5.Longest path with different adjacent characters 72

3
ARRAY
Program 1:
Given an array of integers nums sorted in non-decreasing order, find the starting and ending
position of a given target value.
If target is not found in the array, return [-1, -1].
You must write an algorithm with O(log n) runtime complexity.

Solution:
#include <stdio.h>
#include <stdlib.h>

// Helper function to find the leftmost or rightmost index


int binarySearch(int* nums, int numsSize, int target, int findFirst) {
int left = 0, right = numsSize - 1, result = -1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
result = mid;
if (findFirst) {
right = mid - 1; // Narrow search to the left half
} else {
left = mid + 1; // Narrow search to the right half
}
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}

// Main function to find the starting and ending position


int* searchRange(int* nums, int numsSize, int target, int* returnSize) {
int* result = (int*)malloc(2 * sizeof(int)); // Allocate memory for result
result[0] = binarySearch(nums, numsSize, target, 1); // Find leftmost index
result[1] = binarySearch(nums, numsSize, target, 0); // Find rightmost index
*returnSize = 2; // Set the return size
return result;
}

// Driver function
int sum() {
int nums[] = {5, 7, 7, 8, 8, 10};
int size = sizeof(nums) / sizeof(nums[0]);
int target = 8;
int returnSize;

int* result = searchRange(nums, size, target, &returnSize);

printf("Output: [%d, %d]\n", result[0], result[1]);


4
free(result); // Free allocated memory
return 0;
}

5
Program 2:
Given an array of distinct integers candidates and a target integer target, return a list of all unique
combinations of candidates where the chosen numbers sum to target. You may return the
combinations in any order.
The same number may be chosen from candidates an unlimited number of times. Two
combinations are unique if the
frequency of at least one of the chosen numbers is different.
The test cases are generated such that the number of unique combinations that sum up to target is
less than 150 combinations for the given input.

Solution:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Helper function to add a combination to the result
void addCombination(int** result, int* returnSize, int* columnSizes, int* combination, int
combinationSize) {
result[*returnSize] = (int*)malloc(combinationSize * sizeof(int));
memcpy(result[*returnSize], combination, combinationSize * sizeof(int));
columnSizes[*returnSize] = combinationSize;
(*returnSize)++;
}
// Backtracking function
void backtrack(int* candidates, int candidatesSize, int target, int** result, int* returnSize, int*
columnSizes, int* combination, int combinationSize, int start) {
if (target == 0) {
addCombination(result, returnSize, columnSizes, combination, combinationSize);
return;
}
if (target < 0) return;
for (int i = start; i < candidatesSize; i++) {
combination[combinationSize] = candidates[i];
backtrack(candidates, candidatesSize, target - candidates[i], result, returnSize, columnSizes,
combination, combinationSize + 1, i);
}
}
// Main function
int** combinationSum(int* candidates, int candidatesSize, int target, int* returnSize, int**
columnSizes) {
int** result = (int**)malloc(150 * sizeof(int*)); // Maximum 150 combinations
*returnSize = 0;
*columnSizes = (int*)malloc(150 * sizeof(int));
int* combination = (int*)malloc(target * sizeof(int)); // Maximum length is target

backtrack(candidates, candidatesSize, target, result, returnSize, *columnSizes, combination, 0,


0);
free(combination);
return result;
}
// Driver function
int sum() {
int candidates[] = {2, 3, 6, 7};

6
int target = 7;
int returnSize;
int* columnSizes;
int** result = combinationSum(candidates, sizeof(candidates) / sizeof(candidates[0]), target,
&returnSize, &columnSizes);
printf("Output:\n");
for (int i = 0; i < returnSize; i++) {
printf("[");
for (int j = 0; j < columnSizes[i]; j++) {
printf("%d", result[i][j]);
if (j < columnSizes[i] - 1) printf(", ");
}
printf("]\n");
free(result[i]); // Free each combination
}
free(result); // Free result array
free(columnSizes); // Free columnSizes array
return 0;
}

7
Program 3:
Given an array nums of distinct integers, return all the possible permutations. You can return the
answer in any order.

Solution:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Helper function to add a permutation to the result
void addPermutation(int** result, int* returnSize, int* columnSizes, int* nums, int numsSize) {
result[*returnSize] = (int*)malloc(numsSize * sizeof(int));
memcpy(result[*returnSize], nums, numsSize * sizeof(int));
columnSizes[*returnSize] = numsSize;
(*returnSize)++;
}
// Backtracking function to generate permutations
void backtrack(int* nums, int numsSize, int** result, int* returnSize, int* columnSizes, int start) {
if (start == numsSize) {
addPermutation(result, returnSize, columnSizes, nums, numsSize);
return;
}

for (int i = start; i < numsSize; i++) {


// Swap nums[start] and nums[i]
int temp = nums[start];
nums[start] = nums[i];
nums[i] = temp;
// Recurse with the next position fixed
backtrack(nums, numsSize, result, returnSize, columnSizes, start + 1);
// Backtrack: undo the swap
temp = nums[start];
nums[start] = nums[i];

8
nums[i] = temp;
}
}
// Main function to generate all permutations
int** permute(int* nums, int numsSize, int* returnSize, int** columnSizes) {
int maxPermutations = 1;
for (int i = 2; i <= numsSize; i++) maxPermutations *= i; // numsSize!
int** result = (int**)malloc(maxPermutations * sizeof(int*));
*columnSizes = (int*)malloc(maxPermutations * sizeof(int));
*returnSize = 0;
backtrack(nums, numsSize, result, returnSize, *columnSizes, 0);
return result;
}
// Driver function
int Main() {
int nums[] = {1, 2, 3};
int numsSize = sizeof(nums) / sizeof(nums[0]);
int returnSize;
int* columnSizes;
int** result = permute(nums, numsSize, &returnSize, &columnSizes);
printf("Output:\n");
for (int i = 0; i < returnSize; i++) {
printf("[");
for (int j = 0; j < columnSizes[i]; j++) {
printf("%d", result[i][j]);
if (j < columnSizes[i] - 1) printf(", ");
}
printf("]\n");
free(result[i]); // Free each permutation
}
free(result); // Free result array
free(columnSizes); // Free columnSizes array
return 0;
}

9
Program 4:
Given an integer array nums where every element appears three times except for one, which
appears exactly once. Find the single element and return it. You must implement a solution with a
linear runtime complexity and use only constant extra space.
Solution:
#include <stdio.h>
int singleNumber(int* nums, int numsSize) {
int ones = 0, twos = 0;
for (int i = 0; i < numsSize; i++) {
// Update `twos` with the bits in `ones` that are also in the current number
twos |= ones & nums[i];
// Update `ones` with the current number
ones ^= nums[i];
// Mask to clear bits that appear three times
int threes = ones & twos;
ones &= ~threes;
twos &= ~threes;
}
return ones;
}
10
// Driver function
int Main() {
int nums1[] = {2, 2, 3, 2};
int size1 = sizeof(nums1) / sizeof(nums1[0]);
printf("Output: %d\n", singleNumber(nums1, size1)); // Output: 3

int nums2[] = {0, 1, 0, 1, 0, 1, 99};


int size2 = sizeof(nums2) / sizeof(nums2[0]);
printf("Output: %d\n", singleNumber(nums2, size2)); // Output: 99
return 0;
}

11
Program 5:
Given two sorted arrays nums1 and nums2 of size m and n respectively, return the median of the
two sorted arrays. The overall run time complexity should be O(log (m+n)).
Solution:
#include <stdio.h>
#include <stdlib.h>
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) {
// Ensure that nums1 is the smaller array
if (nums1Size > nums2Size) {
int* temp = nums1;
nums1 = nums2;
nums2 = temp;
int tempSize = nums1Size;
nums1Size = nums2Size;
nums2Size = tempSize;
}
int left = 0, right = nums1Size;
int partition1, partition2;
int maxLeft1, minRight1, maxLeft2, minRight2;
while (left <= right) {
partition1 = (left + right) / 2;
partition2 = (nums1Size + nums2Size + 1) / 2 - partition1;
maxLeft1 = (partition1 == 0) ? INT_MIN : nums1[partition1 - 1];
minRight1 = (partition1 == nums1Size) ? INT_MAX : nums1[partition1];
maxLeft2 = (partition2 == 0) ? INT_MIN : nums2[partition2 - 1];
minRight2 = (partition2 == nums2Size) ? INT_MAX : nums2[partition2];
// Check if partition is correct
if (maxLeft1 <= minRight2 && maxLeft2 <= minRight1) {
// Odd combined length: take the max of the left side
if ((nums1Size + nums2Size) % 2 == 1) {
return fmax(maxLeft1, maxLeft2);
}
// Even combined length: take the average of the max of the left side and min of the right
side
return (fmax(maxLeft1, maxLeft2) + fmin(minRight1, minRight2)) / 2.0;
}
// Move partition1 to the left or right
else if (maxLeft1 > minRight2) {
right = partition1 - 1;
} else {
left = partition1 + 1;
}
}
return 0.0; // Should never reach here if inputs are valid
}
int Main() {
int nums1[] = {1, 3};
int nums2[] = {2};
int nums1Size = sizeof(nums1) / sizeof(nums1[0]);
int nums2Size = sizeof(nums2) / sizeof(nums2[0]);
printf("Median: %.5f\n", findMedianSortedArrays(nums1, nums1Size, nums2, nums2Size)); //
Output: 2.00000

12
int nums1_2[] = {1, 2};
int nums2_2[] = {3, 4};
int nums1Size_2 = sizeof(nums1_2) / sizeof(nums1_2[0]);
int nums2Size_2 = sizeof(nums2_2) / sizeof(nums2_2[0]);
printf("Median: %.5f\n", findMedianSortedArrays(nums1_2, nums1Size_2, nums2_2,
nums2Size_2)); // Output: 2.50000
return 0;
}

13
STACKS
Program 1:
You are given an array of strings tokens that represents an arithmetic expression in a Reverse
Polish Notation. Evaluate the expression. Return an integer that represents the value of the
expression.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int evalRPN(char** tokens, int tokensSize) {
int stack[tokensSize];
int top = -1;
for (int i = 0; i < tokensSize; i++) {
char* token = tokens[i];
if (isdigit(token[0]) || (token[0] == '-' && strlen(token) > 1)) {
// Push the number onto the stack
stack[++top] = atoi(token);
} else {
// Pop the top two elements from the stack
int b = stack[top--];
int a = stack[top--];
// Perform the operation
if (strcmp(token, "+") == 0) {
stack[++top] = a + b;
} else if (strcmp(token, "-") == 0) {
stack[++top] = a - b;
} else if (strcmp(token, "*") == 0) {
stack[++top] = a * b;
} else if (strcmp(token, "/") == 0) {
stack[++top] = a / b;
}
}
}
// The result is the only element left in the stack
return stack[top];
}
int Main() {
// Example 1
char* tokens1[] = {"2", "1", "+", "3", "*"};
int tokensSize1 = sizeof(tokens1) / sizeof(tokens1[0]);
printf("Output: %d\n", evalRPN(tokens1, tokensSize1)); // Output: 9
// Example 2
char* tokens2[] = {"4", "13", "5", "/", "+"};
int tokensSize2 = sizeof(tokens2) / sizeof(tokens2[0]);
printf("Output: %d\n", evalRPN(tokens2, tokensSize2)); // Output: 6
// Example 3
char* tokens3[] = {"10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"};
int tokensSize3 = sizeof(tokens3) / sizeof(tokens3[0]);
printf("Output: %d\n", evalRPN(tokens3, tokensSize3)); // Output: 22
return 0;
}

14
15
Program 2:
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
Implement the MinStack class:
MinStack() initializes the stack object.
void push(int val) pushes the element val onto the stack.
void pop() removes the element on the top of the stack.
int top() gets the top element of the stack.
int getMin() retrieves the minimum element in the stack.
You must implement a solution with O(1) time complexity for each function.

Solution:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct {
int *stack;
int *minStack;
int top;
int minTop;
int capacity;
} MinStack;
/** Initialize your data structure here. */
MinStack* minStackCreate() {
MinStack* obj = (MinStack*)malloc(sizeof(MinStack));
obj->capacity = 30000; // Maximum calls limit
obj->stack = (int*)malloc(obj->capacity * sizeof(int));
obj->minStack = (int*)malloc(obj->capacity * sizeof(int));
obj->top = -1;
obj->minTop = -1;
return obj;
}
/** Push element onto stack. */
void minStackPush(MinStack* obj, int val) {
obj->stack[++(obj->top)] = val;
if (obj->minTop == -1 || val <= obj->minStack[obj->minTop]) {
obj->minStack[++(obj->minTop)] = val;
}
}
/** Remove the element on top of the stack. */
void minStackPop(MinStack* obj) {
if (obj->top == -1) return; // Stack is empty
if (obj->stack[obj->top] == obj->minStack[obj->minTop]) {
obj->minTop--; // Pop from minStack
}
obj->top--; // Pop from main stack
}
/** Get the top element. */
int minStackTop(MinStack* obj) {
return obj->stack[obj->top];

16
}
/** Retrieve the minimum element in the stack. */
int minStackGetMin(MinStack* obj) {
return obj->minStack[obj->minTop];
}
/** Free memory allocated for the stack. */
void minStackFree(MinStack* obj) {
free(obj->stack);
free(obj->minStack);
free(obj);
}
/** Example Usage */
int Main() {
MinStack* minStack = minStackCreate();
minStackPush(minStack, -2);
minStackPush(minStack, 0);
minStackPush(minStack, -3);
printf("Minimum: %d\n", minStackGetMin(minStack)); // Output: -3
minStackPop(minStack);
printf("Top: %d\n", minStackTop(minStack)); // Output: 0
printf("Minimum: %d\n", minStackGetMin(minStack)); // Output: -2
minStackFree(minStack);
return 0;
}

17
Program 3:
Given a string s which represents an expression, evaluate this expression and return its value.
The integer division should truncate toward zero.
You may assume that the given expression is always valid. All intermediate results will be in the
range of [-231, 231 - 1].

Solution:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
typedef struct {
int* data;
int top;
int capacity;
} Stack;
// Initialize a new stack
Stack* createStack(int initialCapacity) {
Stack* stack = (Stack*)malloc(sizeof(Stack));
stack->data = (int*)malloc(initialCapacity * sizeof(int));
stack->top = -1;
stack->capacity = initialCapacity;
return stack;
}
// Push an element onto the stack
void push(Stack* stack, int value) {
if (stack->top == stack->capacity - 1) {
stack->capacity *= 2;
stack->data = (int*)realloc(stack->data, stack->capacity * sizeof(int));
}
stack->data[++(stack->top)] = value;
}
// Pop an element from the stack
int pop(Stack* stack) {
if (stack->top == -1) {
return 0; // Stack underflow
}
return stack->data[(stack->top)--];
}
// Peek the top element of the stack
int peek(Stack* stack) {
if (stack->top == -1) {
return 0; // Stack is empty
}
return stack->data[stack->top];
}
// Free the stack
void freeStack(Stack* stack) {
free(stack->data);
free(stack);
}
// Evaluate the expression

18
int calculate(char* s) {
Stack* stack = createStack(100); // Start with a capacity of 100
int currentNumber = 0;
char operation = '+';
for (int i = 0; s[i] != '\0'; i++) {
char ch = s[i];
// If the character is a digit, build the current number
if (isdigit(ch)) {
currentNumber = currentNumber * 10 + (ch - '0');
}
// If the character is an operator or end of string, process the operation
if ((!isdigit(ch) && !isspace(ch)) || s[i + 1] == '\0') {
if (operation == '+') {
push(stack, currentNumber);
} else if (operation == '-') {
push(stack, -currentNumber);
} else if (operation == '*') {
int topValue = pop(stack);
push(stack, topValue * currentNumber);
} else if (operation == '/') {
int topValue = pop(stack);
push(stack, topValue / currentNumber);
}
// Update the operation and reset currentNumber
operation = ch;
currentNumber = 0;
}
}
// Sum up all the values in the stack
int result = 0;
while (stack->top != -1) {
result += pop(stack);
}
freeStack(stack);
return result;
}
int Main() {
char s1[] = "3+2*2";
printf("Output: %d\n", calculate(s1)); // Output: 7

char s2[] = " 3/2 ";


printf("Output: %d\n", calculate(s2)); // Output: 1

char s3[] = " 3+5 / 2 ";


printf("Output: %d\n", calculate(s3)); // Output: 5

return 0;
}

19
20
Program 4:
Given an encoded string, return its decoded string.
The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is
being repeated exactly k times. Note that k is guaranteed to be a positive integer.
You may assume that the input string is always valid; there are no extra white spaces, square
brackets are well-formed, etc. Furthermore, you may assume that the original data does not contain
any digits and that digits are only for those repeat numbers, k. For example, there will not be input
like 3a or 2[4]. The test cases are generated so that the length of the output will never exceed 105.
Solution:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// Helper function to repeat a string 'k' times
char* repeatString(const char* str, int k) {
int len = strlen(str);
char* result = (char*)malloc(len * k + 1); // Allocate memory for repeated string
result[0] = '\0'; // Initialize the string
for (int i = 0; i < k; i++) {
strcat(result, str);
}
return result;
}
char* decodeString(const char* s) {
int capacity = 1000; // Initial capacity for the current string buffer
char* current = (char*)malloc(capacity);
current[0] = '\0'; // Initialize the current string
int count = 0; // Current multiplier
// Stacks for strings and counts
char* stackStr[100];
int stackCount[100];
int top = -1;
for (int i = 0; s[i] != '\0'; i++) {
if (isdigit(s[i])) {
// Parse the full number
count = count * 10 + (s[i] - '0');
} else if (s[i] == '[') {
// Push current state onto stacks
stackStr[++top] = strdup(current);
stackCount[top] = count;
current[0] = '\0'; // Reset current string
count = 0; // Reset count
} else if (s[i] == ']') {
// Pop from stacks and decode
char* temp = repeatString(current, stackCount[top]);
char* previous = stackStr[top--];
// Ensure buffer is large enough to hold concatenated result
int newLen = strlen(previous) + strlen(temp) + 1;
if (newLen > capacity) {
capacity = newLen;
current = (char*)realloc(current, capacity);
}

21
strcpy(current, previous); // Start with the previous string
strcat(current, temp); // Append the repeated string
free(temp);
free(previous);
} else {
// Append character to the current string
int len = strlen(current);
if (len + 2 > capacity) { // Ensure space for new character and null terminator
capacity *= 2;
current = (char*)realloc(current, capacity);
}
current[len] = s[i];
current[len + 1] = '\0';
}
}
return current; // Return the decoded string
}
int Main() {
char s1[] = "3[a]2[bc]";
printf("Output: %s\n", decodeString(s1)); // Output: "aaabcbc"

char s2[] = "3[a2[c]]";


printf("Output: %s\n", decodeString(s2)); // Output: "accaccacc"

char s3[] = "2[abc]3[cd]ef";


printf("Output: %s\n", decodeString(s3)); // Output: "abcabccdcdcdef"

char s4[] = "100[leetcode]";


printf("Output: %s\n", decodeString(s4)); // Output: "leetcode" repeated 100 times

return 0;
}

22
23
Program 5:
Given a string containing just the characters '(' and ')', return the length of the longest valid (well-
formed) parentheses substring.

Solution:
#include <stdio.h>
#include <string.h>
int longestValidParentheses(char* s) {
int maxLen = 0;
int n = strlen(s);
int stack[n + 1]; // Stack to store indices
int top = -1; // Top pointer for the stack
stack[++top] = -1; // Initialize stack with a base index
for (int i = 0; i < n; i++) {
if (s[i] == '(') {
stack[++top] = i; // Push index of '(' onto the stack
} else {
top--; // Pop the stack for ')'
if (top == -1) {
stack[++top] = i; // Update base index for invalid ')'
} else {
int len = i - stack[top];
if (len > maxLen) {
maxLen = len;
}
}
}
}

return maxLen;
}
int Main() {
char s1[] = "(()";
char s2[] = ")()())";
char s3[] = "";

printf("Input: \"%s\", Output: %d\n", s1, longestValidParentheses(s1)); // Output: 2


printf("Input: \"%s\", Output: %d\n", s2, longestValidParentheses(s2)); // Output: 4
printf("Input: \"%s\", Output: %d\n", s3, longestValidParentheses(s3)); // Output: 0
return 0;
}

24
25
QUEUES
Program 1:
Given a string s, find the first non-repeating character in it and return its index. If it does not exist,
return -1.

Solution:
#include <stdio.h>
#include <string.h>
int firstUniqChar(char *s) {
int freq[26] = {0}; // Array to count the frequency of each character
int n = strlen(s);
// First pass: count the frequency of each character
for (int i = 0; i < n; i++) {
freq[s[i] - 'a']++;
}
// Second pass: find the first character with frequency 1
for (int i = 0; i < n; i++) {
if (freq[s[i] - 'a'] == 1) {
return i; // Return the index of the first non-repeating character
}
}
return -1; // If no non-repeating character is found, return -1
}
// Test the function with examples
int Main() {
printf("Result 1: %d\n", firstUniqChar("leetcode")); // Expected output: 0
printf("Result 2: %d\n", firstUniqChar("loveleetcode")); // Expected output: 2
printf("Result 3: %d\n", firstUniqChar("aabb")); // Expected output: -1

return 0;
}

26
Program 2:
Design your implementation of the circular queue. The circular queue is a linear data structure in
which the operations are performed based on FIFO (First In First Out) principle, and the last
position is connected back to the first position to make a circle. It is also called "Ring Buffer".
One of the benefits of the circular queue is that we can make use of the spaces in front of the queue.
In a normal queue, once the queue becomes full, we cannot insert the next element even if there is a
space in front of the queue. But using the circular queue, we can use the space to store new values.
Implement the MyCircularQueue class:
• MyCircularQueue(k) Initializes the object with the size of the queue to be k.
• int Front() Gets the front item from the queue. If the queue is empty, return -1.
• int Rear() Gets the last item from the queue. If the queue is empty, return -1.
• boolean enQueue(int value) Inserts an element into the circular queue. Return true if the
operation is successful.
• boolean deQueue() Deletes an element from the circular queue. Return true if the operation
is successful.
• boolean isEmpty() Checks whether the circular queue is empty or not.
• boolean isFull() Checks whether the circular queue is full or not.
You must solve the problem without using the built-in queue data structure in your programming
language.

27
Solution:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct {
int* data;
int head;
int tail;
int size;
int capacity;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* queue = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
queue->data = (int*)malloc(sizeof(int) * k);
queue->head = -1;
queue->tail = -1;
queue->size = 0;
queue->capacity = k;
return queue;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if (obj->size == obj->capacity) {
return false; // Queue is full
}
if (obj->size == 0) {
obj->head = 0;
}
obj->tail = (obj->tail + 1) % obj->capacity;
obj->data[obj->tail] = value;
obj->size++;
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if (obj->size == 0) {
return false; // Queue is empty
}
if (obj->size == 1) {
obj->head = -1;
obj->tail = -1;
} else {
obj->head = (obj->head + 1) % obj->capacity;
}
obj->size--;
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if (obj->size == 0) {
return -1; // Queue is empty
}
return obj->data[obj->head];
}
int myCircularQueueRear(MyCircularQueue* obj) {

28
if (obj->size == 0) {
return -1; // Queue is empty
}
return obj->data[obj->tail];
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->size == 0;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {


return obj->size == obj->capacity;
}

void myCircularQueueFree(MyCircularQueue* obj) {


free(obj->data);
free(obj);
}
int Main() {
MyCircularQueue* myCircularQueue = myCircularQueueCreate(3);
printf("%d\n", myCircularQueueEnQueue(myCircularQueue, 1)); // return true
printf("%d\n", myCircularQueueEnQueue(myCircularQueue, 2)); // return true
printf("%d\n", myCircularQueueEnQueue(myCircularQueue, 3)); // return true
printf("%d\n", myCircularQueueEnQueue(myCircularQueue, 4)); // return false
printf("%d\n", myCircularQueueRear(myCircularQueue)); // return 3
printf("%d\n", myCircularQueueIsFull(myCircularQueue)); // return true
printf("%d\n", myCircularQueueDeQueue(myCircularQueue)); // return true
printf("%d\n", myCircularQueueEnQueue(myCircularQueue, 4)); // return true
printf("%d\n", myCircularQueueRear(myCircularQueue)); // return 4
myCircularQueueFree(myCircularQueue);
return 0;
}

29
Program 3:
You are given a 0-indexed integer array nums. A subarray of nums is called continuous if:
• Let i, i + 1, ..., j be the indices in the subarray. Then, for each pair of indices i <= i1, i2 <=
j, 0 <= |nums[i1] - nums[i2]| <= 2.
Return the total number of continuous subarrays.
A subarray is a contiguous non-empty sequence of elements within an array.

Solution:
#include <stdio.h>
#include <stdlib.h>
long long continuousSubarrays(int* nums, int numsSize) {
long long count = 0; // Total number of continuous subarrays
int left = 0; // Left pointer of the sliding window
int minVal = nums[0]; // Minimum value in the current window
int maxVal = nums[0]; // Maximum value in the current window
for (int right = 0; right < numsSize; right++) {
// Update the min and max values in the current window
if (nums[right] < minVal) {
minVal = nums[right];
}
if (nums[right] > maxVal) {
maxVal = nums[right];
}
// If the condition is violated, shrink the window from the left
while (maxVal - minVal > 2) {
left++;
// Update minVal and maxVal after moving the left pointer
minVal = nums[left];
maxVal = nums[left];
for (int k = left; k <= right; k++) {
if (nums[k] < minVal) minVal = nums[k];
if (nums[k] > maxVal) maxVal = nums[k];
}
}
// All subarrays ending at 'right' are valid
count += (right - left + 1);
}
return count;
}
int Main() {
int nums1[] = {5, 4, 2, 4};
int numsSize1 = sizeof(nums1) / sizeof(nums1[0]);
printf("Output: %lld\n", continuousSubarrays(nums1, numsSize1)); // Output: 8
int nums2[] = {1, 2, 3};
int numsSize2 = sizeof(nums2) / sizeof(nums2[0]);
printf("Output: %lld\n", continuousSubarrays(nums2, numsSize2)); // Output: 6
return 0;
}

30
Program 4:
Design your implementation of the circular double-ended queue (deque).
Implement the MyCircularDeque class:
• MyCircularDeque(int k) Initializes the deque with a maximum size of k.
• boolean insertFront() Adds an item at the front of Deque. Returns true if the operation is
successful, or false otherwise.
• boolean insertLast() Adds an item at the rear of Deque. Returns true if the operation is
successful, or false otherwise.
• boolean deleteFront() Deletes an item from the front of Deque. Returns true if the operation
is successful, or false otherwise.
• boolean deleteLast() Deletes an item from the rear of Deque. Returns true if the operation is
successful, or false otherwise.
• int getFront() Returns the front item from the Deque. Returns -1 if the deque is empty.
• int getRear() Returns the last item from Deque. Returns -1 if the deque is empty.
• boolean isEmpty() Returns true if the deque is empty, or false otherwise.
• boolean isFull() Returns true if the deque is full, or false otherwise.

31
Solution:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct {
int* data;
int front;
int rear;
int capacity;
int size;
} MyCircularDeque;
MyCircularDeque* myCircularDequeCreate(int k) {
MyCircularDeque* obj = (MyCircularDeque*)malloc(sizeof(MyCircularDeque));
obj->data = (int*)malloc(sizeof(int) * k);
obj->capacity = k;
obj->size = 0;
obj->front = 0;
obj->rear = k - 1; // Rear starts at the end of the array
return obj;
}
bool myCircularDequeInsertFront(MyCircularDeque* obj, int value) {
if (obj->size == obj->capacity) return false; // Deque is full
obj->front = (obj->front - 1 + obj->capacity) % obj->capacity;
obj->data[obj->front] = value;
obj->size++;
return true;
}
bool myCircularDequeInsertLast(MyCircularDeque* obj, int value) {
if (obj->size == obj->capacity) return false; // Deque is full
obj->rear = (obj->rear + 1) % obj->capacity;
obj->data[obj->rear] = value;
obj->size++;
return true;
}
bool myCircularDequeDeleteFront(MyCircularDeque* obj) {
if (obj->size == 0) return false; // Deque is empty
obj->front = (obj->front + 1) % obj->capacity;
obj->size--;
return true;
}
bool myCircularDequeDeleteLast(MyCircularDeque* obj) {
if (obj->size == 0) return false; // Deque is empty
obj->rear = (obj->rear - 1 + obj->capacity) % obj->capacity;
obj->size--;
return true;
}
int myCircularDequeGetFront(MyCircularDeque* obj) {
if (obj->size == 0) return -1; // Deque is empty
return obj->data[obj->front];
}
int myCircularDequeGetRear(MyCircularDeque* obj) {
if (obj->size == 0) return -1; // Deque is empty

32
return obj->data[obj->rear];
}
bool myCircularDequeIsEmpty(MyCircularDeque* obj) {
return obj->size == 0;
}
bool myCircularDequeIsFull(MyCircularDeque* obj) {
return obj->size == obj->capacity;
}
void myCircularDequeFree(MyCircularDeque* obj) {
free(obj->data);
free(obj);
}
int Main() {
MyCircularDeque* myCircularDeque = myCircularDequeCreate(3);
printf("%d\n", myCircularDequeInsertLast(myCircularDeque, 1)); // return True
printf("%d\n", myCircularDequeInsertLast(myCircularDeque, 2)); // return True
printf("%d\n", myCircularDequeInsertFront(myCircularDeque, 3)); // return True
printf("%d\n", myCircularDequeInsertFront(myCircularDeque, 4)); // return False (full)
printf("%d\n", myCircularDequeGetRear(myCircularDeque)); // return 2
printf("%d\n", myCircularDequeIsFull(myCircularDeque)); // return True
printf("%d\n", myCircularDequeDeleteLast(myCircularDeque)); // return True
printf("%d\n", myCircularDequeInsertFront(myCircularDeque, 4)); // return True
printf("%d\n", myCircularDequeGetFront(myCircularDeque)); // return 4
myCircularDequeFree(myCircularDeque);
return 0;
}

33
Program 5:
Given an integer array nums and an integer k, return the length of the shortest non-
empty subarray of nums with a sum of at least k. If there is no such subarray, return -1.
A subarray is a contiguous part of an array.

Solution:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int shortestSubarray(int* nums, int numsSize, int k) {
// Prefix sum array
long* prefixSum = (long*)malloc((numsSize + 1) * sizeof(long));
prefixSum[0] = 0;
for (int i = 0; i < numsSize; i++) {
prefixSum[i + 1] = prefixSum[i] + nums[i];
}
// Deque to maintain indices of prefix sums
int* deque = (int*)malloc((numsSize + 1) * sizeof(int));
int front = 0, rear = 0;
int minLength = INT_MAX;
for (int i = 0; i <= numsSize; i++) {
// Remove elements from the front of the deque if the current prefix sum - deque front prefix
sum >= k
while (front < rear && prefixSum[i] - prefixSum[deque[front]] >= k) {
minLength = fmin(minLength, i - deque[front]);
front++;
}
// Maintain the monotonic property of the deque
while (front < rear && prefixSum[i] <= prefixSum[deque[rear - 1]]) {
rear--;
}
// Add the current index to the deque
deque[rear++] = i;
}
free(prefixSum);
free(deque);
return (minLength == INT_MAX) ? -1 : minLength;
}
int Main() {
int nums1[] = {1};
int k1 = 1;
printf("Output: %d\n", shortestSubarray(nums1, 1, k1)); // Output: 1
int nums2[] = {1, 2};
int k2 = 4;
printf("Output: %d\n", shortestSubarray(nums2, 2, k2)); // Output: -1
int nums3[] = {2, -1, 2};
int k3 = 3;
printf("Output: %d\n", shortestSubarray(nums3, 3, k3)); // Output: 3
return 0;
}

34
35
LINKED LIST
Program 1:
Given the head of a linked list, remove the nth node from the end of the list and return its head.

Solution:
#include <stdio.h>
#include <stdlib.h>
// Definition for singly-linked list.
struct listNode {
int val;
struct ListNode* next;
};
// Function to remove the nth node from the end of the list
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
struct ListNode* dummy = (struct ListNode*)malloc(sizeof(struct ListNode));
dummy->next = head;
struct ListNode* first = dummy;
struct ListNode* second = dummy;
// Move first pointer n+1 steps ahead
for (int i = 0; i <= n; i++) {
first = first->next;
}
// Move both pointers until the first reaches the end
while (first != NULL) {
first = first->next;
second = second->next;
}
// Remove the nth node from the end
struct ListNode* temp = second->next;
second->next = second->next->next;
free(temp);
return dummy->next; // Return the head of the modified list
}
// Helper function to create a linked list from an array
struct ListNode* createList(int* arr, int size) {
struct ListNode* head = NULL;
struct ListNode* tail = NULL;

for (int i = 0; i < size; i++) {


struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
newNode->val = arr[i];
newNode->next = NULL;
if (head == NULL) {
head = newNode;
tail = head;
} else {
tail->next = newNode;
tail = tail->next;
}
}
return head;
}
36
// Helper function to print a linked list
void printList(struct ListNode* head) {
while (head != NULL) {
printf("%d", head->val);
if (head->next != NULL) {
printf(" -> ");
}
head = head->next;
}
printf("\n");
}
int Main() {
// Example 1: head = [1,2,3,4,5], n = 2
int arr1[] = {1, 2, 3, 4, 5};
struct ListNode* head1 = createList(arr1, 5);
struct ListNode* result1 = removeNthFromEnd(head1, 2);
printf("Output: ");
printList(result1); // Expected Output: 1 -> 2 -> 3 -> 5
// Example 2: head = [1], n = 1
int arr2[] = {1};
struct ListNode* head2 = createList(arr2, 1);
struct ListNode* result2 = removeNthFromEnd(head2, 1);
printf("Output: ");
printList(result2); // Expected Output: (empty list)

// Example 3: head = [1,2], n = 1


int arr3[] = {1, 2};
struct ListNode* head3 = createList(arr3, 2);
struct ListNode* result3 = removeNthFromEnd(head3, 1);
printf("Output: ");
printList(result3); // Expected Output: 1
return 0;
}

37
Program 2:
You are given two non-empty linked lists representing two non-negative integers. The digits are
stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and
return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Solution:
#include <stdio.h>
#include <stdlib.h>
// Definition for singly-linked list.
struct listNode{
int val;
struct ListNode* next;
};
// Helper function to create a new node
struct ListNode* createNode(int value) {
38
struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
newNode->val = value;
newNode->next = NULL;
return newNode;
}
// Function to add two numbers represented by linked lists
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
struct ListNode dummy; // Dummy node to simplify code
struct ListNode* current = &dummy;
dummy.next = NULL;
int carry = 0;
while (l1 != NULL || l2 != NULL || carry) {
int sum = carry;
if (l1 != NULL) {
sum += l1->val;
l1 = l1->next;
}
if (l2 != NULL) {
sum += l2->val;
l2 = l2->next;
}
carry = sum / 10; // Calculate carry for the next digit
current->next = createNode(sum % 10); // Create a new node with the current digit
current = current->next;
}
return dummy.next; // Return the result linked list
}
// Helper function to print a linked list
void printList(struct ListNode* head) {
while (head != NULL) {
printf("%d", head->val);
if (head->next != NULL) printf(" -> ");
head = head->next;
}
printf("\n");
}
// Helper function to create a linked list from an array
struct ListNode* createList(int* arr, int size) {
struct ListNode* head = NULL;
struct ListNode* tail = NULL;
for (int i = 0; i < size; i++) {
struct ListNode* newNode = createNode(arr[i]);
if (head == NULL) {
head = newNode;
tail = head;
} else {
tail->next = newNode;
tail = tail->next;
}
}
return head;
}

39
int Main() {
// Example 1
int arr1[] = {2, 4, 3};
int arr2[] = {5, 6, 4};
struct ListNode* l1 = createList(arr1, 3);
struct ListNode* l2 = createList(arr2, 3);
struct ListNode* result = addTwoNumbers(l1, l2);
printf("Output: ");
printList(result); // Output: 7 -> 0 -> 8
// Example 2
int arr3[] = {0};
int arr4[] = {0};
l1 = createList(arr3, 1);
l2 = createList(arr4, 1);
result = addTwoNumbers(l1, l2);
printf("Output: ");
printList(result); // Output: 0
// Example 3
int arr5[] = {9, 9, 9, 9, 9, 9, 9};
int arr6[] = {9, 9, 9, 9};
l1 = createList(arr5, 7);
l2 = createList(arr6, 4);
result = addTwoNumbers(l1, l2);
printf("Output: ");
printList(result); // Output: 8 -> 9 -> 9 -> 9 -> 0 -> 0 -> 0 -> 1
return 0;
}

40
Program 3:
Given a linked list, swap every two adjacent nodes and return its head. You must solve the problem
without modifying the values in the list's nodes (i.e., only nodes themselves may be changed.)
Solution:
#include <stdio.h>
#include <stdlib.h>
// Definition for singly-linked list.
struct listNode {
int val;
struct ListNode* next;
};
// Function to swap every two adjacent nodes
struct ListNode* swapPairs(struct ListNode* head) {
// Create a dummy node to simplify the code
struct ListNode* dummy = (struct ListNode*)malloc(sizeof(struct ListNode));
dummy->next = head;
struct ListNode* current = dummy;
// Traverse the list in pairs
while (current->next != NULL && current->next->next != NULL) {
41
struct ListNode* first = current->next;
struct ListNode* second = current->next->next;
// Swap the nodes by adjusting the next pointers
first->next = second->next;
second->next = first;
current->next = second;
// Move current to the next pair
current = first;
}
// Return the new head, which is the next node of dummy
return dummy->next;
}
// Helper function to create a linked list from an array
struct ListNode* createList(int* arr, int size) {
struct ListNode* head = NULL;
struct ListNode* tail = NULL;
for (int i = 0; i < size; i++) {
struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
newNode->val = arr[i];
newNode->next = NULL;
if (head == NULL) {
head = newNode;
tail = head;
} else {
tail->next = newNode;
tail = tail->next;
}
}
return head;
}
// Helper function to print a linked list
void printList(struct ListNode* head) {
if (head == NULL) {
printf("List is empty\n");
return;
}
while (head != NULL) {
printf("%d", head->val);
if (head->next != NULL) {
printf(" -> ");
}
head = head->next;
}
printf("\n");
}
int Main() {
// Example 1: Input: head = [1,2,3,4]
int arr1[] = {1, 2, 3, 4};
struct ListNode* list1 = createList(arr1, 4);
printf("Original List: ");
printList(list1);
struct ListNode* swappedList1 = swapPairs(list1);

42
printf("Swapped List: ");
printList(swappedList1); // Expected Output: 2 -> 1 -> 4 -> 3
// Example 2: Input: head = []
struct ListNode* list2 = NULL;
struct ListNode* swappedList2 = swapPairs(list2);
printf("Swapped List: ");
printList(swappedList2); // Expected Output: (empty list)
// Example 3: Input: head = [1]
int arr3[] = {1};
struct ListNode* list3 = createList(arr3, 1);
printf("Original List: ");
printList(list3);
struct ListNode* swappedList3 = swapPairs(list3);
printf("Swapped List: ");
printList(swappedList3); // Expected Output: 1 (no change)
// Example 4: Input: head = [1,2,3]
int arr4[] = {1, 2, 3};
struct ListNode* list4 = createList(arr4, 3);
printf("Original List: ");
printList(list4);
struct ListNode* swappedList4 = swapPairs(list4);
printf("Swapped List: ");
printList(swappedList4); // Expected Output: 2 -> 1 -> 3
return 0;
}

43
44
Program 4:
Given the head of a singly linked list and two integers left and right where left <= right, reverse the
nodes of the list from position left to position right, and return the reversed list.
Solution:
#include <stdio.h>
#include <stdlib.h>
// Definition for singly-linked list.
struct listNode {
int val;
struct ListNode* next;
};
// Function to reverse the sublist between left and right positions
struct ListNode* reverseBetween(struct ListNode* head, int left, int right) {
// If the list is empty or left == right, return the original list
if (head == NULL || left == right) {
return head;
}
// Dummy node to handle the edge case when reversing starts from the head
struct ListNode* dummy = (struct ListNode*)malloc(sizeof(struct ListNode));
dummy->next = head;
struct ListNode* prev = dummy;
// Traverse to the node just before the left-th node
for (int i = 0; i < left - 1; i++) {
prev = prev->next;
}
// Start reversing the sublist from left to right
struct ListNode* current = prev->next;
struct ListNode* next = NULL;
for (int i = 0; i < right - left; i++) {
next = current->next; // Save the next node
current->next = next->next; // Remove next node from current position
next->next = prev->next; // Insert next node before the left-th node
prev->next = next; // Move prev's next to point to next
}

return dummy->next;
}
// Helper function to create a linked list from an array
struct ListNode* createList(int* arr, int size) {
struct ListNode* head = NULL;
struct ListNode* tail = NULL;
for (int i = 0; i < size; i++) {
struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
newNode->val = arr[i];
newNode->next = NULL;
if (head == NULL) {
head = newNode;
tail = head;
} else {
tail->next = newNode;
tail = tail->next;
}

45
}
return head;
}
// Helper function to print a linked list
void printList(struct ListNode* head) {
if (head == NULL) {
printf("List is empty\n");
return;
}
while (head != NULL) {
printf("%d", head->val);
if (head->next != NULL) {
printf(" -> ");
}
head = head->next;
}
printf("\n");
}
int Main() {
// Example 1: Input: head = [1,2,3,4,5], left = 2, right = 4
int arr1[] = {1, 2, 3, 4, 5};
struct ListNode* list1 = createList(arr1, 5);
printf("Original List: ");
printList(list1);
struct ListNode* result1 = reverseBetween(list1, 2, 4);
printf("Reversed List: ");
printList(result1); // Expected Output: 1 -> 4 -> 3 -> 2 -> 5
// Example 2: Input: head = [5], left = 1, right = 1
int arr2[] = {5};
struct ListNode* list2 = createList(arr2, 1);
printf("Original List: ");
printList(list2);
struct ListNode* result2 = reverseBetween(list2, 1, 1);
printf("Reversed List: ");
printList(result2); // Expected Output: 5
return 0;
}

46
Program 5:
Design a data structure to store the strings' count with the ability to return the strings with minimum
and maximum counts.
Solution:
#include <unordered_map>
#include <unordered_set>
#include <string>
class Node {
public:
Node *prev; // Pointer to the previous node in the doubly linked list
Node *next; // Pointer to the next node in the doubly linked list
int count; // Count of occurrences for this node
std::unordered_set<std::string> keys; // Set of keys with this occurrence count
// Constructor for sentinel node
Node() : prev(nullptr), next(nullptr), count(0) {}
// Constructor for actual nodes with a given key and count
Node(const std::string& key, int count) : prev(nullptr), next(nullptr), count(count) {
keys.insert(key);
}

47
// Method to insert a node after this node
Node* insert(Node* node) {
node->prev = this;
node->next = this->next;
this->next->prev = node;
this->next = node;
return node;
}
// Remove the node from the doubly linked list
void remove() {
this->prev->next = this->next;
this->next->prev = this->prev;
}
};
class AllOne {
private:
Node root; // Sentinel node to mark the beginning and end of the doubly linked list
std::unordered_map<std::string, Node*> nodes; // Mapping from keys to their corresponding
nodes
public:
AllOne() {
// Initialize the doubly linked list with the sentinel node linking to itself
root.next = &root;
root.prev = &root;
}
void inc(const std::string& key) {
// Increase the count for the key
if (nodes.find(key) == nodes.end()) {
// If key is new, insert it into the list
if (root.next == &root || root.next->count > 1) {
nodes[key] = root.insert(new Node(key, 1));
} else {
root.next->keys.insert(key);
nodes[key] = root.next;
}
} else {
// If the key already exists, move it to a new or next existing Node
Node *current = nodes[key];
Node *next = current->next;
if (next == &root || next->count > current->count + 1) {
nodes[key] = current->insert(new Node(key, current->count + 1));
} else {
next->keys.insert(key);
nodes[key] = next;
}
// Remove the key from the current Node and delete the Node if it's empty
current->keys.erase(key);
if (current->keys.empty()) {
current->remove();
delete current; // C++ requires explicit deletion
}
}

48
}
void dec(const std::string& key) {
auto it = nodes.find(key);
if (it == nodes.end()) return;
Node *current = it->second;
if (current->count == 1) {
// Remove the key completely if the count is 1
nodes.erase(key);
} else {
// Move the key to previous Node or create a new Node
Node *prev = current->prev;
if (prev == &root || prev->count < current->count - 1) {
nodes[key] = prev->insert(new Node(key, current->count - 1));
} else {
prev->keys.insert(key);
nodes[key] = prev;
}
}
// Remove the key from the current Node and delete the Node if empty
current->keys.erase(key);
if (current->keys.empty()) {
current->remove();
delete current; // C++ requires explicit deletion
}}
std::string getMaxKey() {
if (root.prev == &root) return ""; // Handle case with no key
return *root.prev->keys.begin();
}
std::string getMinKey() {
// Return a key with the minimum count
if (root.next == &root) return ""; // Handle case with no keys
return *root.next->keys.begin();
}
};

49
TREES
Program 1:
Given the root of a binary tree, return the inorder traversal of its nodes' values

Solution:
#include <stdio.h>
#include <stdlib.h>
// Definition for a binary tree node.
struct treeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
};
// Helper function for inorder traversal
void inorderHelper(struct TreeNode* root, int* result, int* index) {
if (root == NULL) {
return;
}
// Traverse the left subtree
inorderHelper(root->left, result, index);

// Visit the root node


result[*index] = root->val;
(*index)++;
// Traverse the right subtree
inorderHelper(root->right, result, index);
}
// Main function to return inorder traversal
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
int* result = (int*)malloc(100 * sizeof(int)); // Assuming there are at most 100 nodes
int index = 0;
inorderHelper(root, result, &index);

*returnSize = index; // Set the size of the result


return result;
}
// Function to create a new tree node
struct TreeNode* createNode(int val) {
struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
node->val = val;
node->left = NULL;
node->right = NULL;
return node;
}
int Main() {
// Example 1: root = [1, null, 2, 3]
struct TreeNode* root = createNode(1);
root->right = createNode(2);
root->right->left = createNode(3);
int returnSize;
int* result = inorderTraversal(root, &returnSize);
// Print result
50
for (int i = 0; i < returnSize; i++) {
printf("%d ", result[i]);
}
printf("\n");
free(result); // Free allocated memory for result
return 0;
}

51
Program 2:
Given an integer n, return the number of structurally unique BST's (binary search trees) which has
exactly n nodes of unique values from 1 to n.
Solution:
#include <stdio.h>
int numTrees(int n) {
// dp[i] will store the number of unique BSTs that can be formed with i nodes
int dp[n + 1];
dp[0] = 1; // One tree can be formed with 0 nodes (empty tree)
dp[1] = 1; // One tree can be formed with 1 node
// Calculate dp[i] for all i from 2 to n
for (int i = 2; i <= n; i++) {
dp[i] = 0;
// For each number of nodes, find the number of BSTs by choosing a root
// from 1 to i, and calculating the number of BSTs in the left and right subtrees
for (int j = 1; j <= i; j++) {
dp[i] += dp[j - 1] * dp[i - j];
}
}
// The result is stored in dp[n]
return dp[n];
}
int Main() {
int n = 3;
printf("Number of unique BSTs with %d nodes: %d\n", n, numTrees(n));
n = 1;
printf("Number of unique BSTs with %d node: %d\n", n, numTrees(n));
return 0;
}

52
Program 3:
Given the root of a binary tree, flatten the tree into a "linked list":
• The "linked list" should use the same TreeNode class where the right child pointer points to
the next node in the list and the left child pointer is always null.
• The "linked list" should be in the same order as a pre-order traversal of the binary tree.
Solution:
#include <stdio.h>
#include <stdlib.h>
// Define the TreeNode structure
struct treeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
};
// Helper function to flatten the tree
void flatten(struct TreeNode* root) {
if (root == NULL) {
return;
}

53
// Flatten the left and right subtree
if (root->left) {
flatten(root->left);
// Find the rightmost node of the left subtree
struct TreeNode* temp = root->left;
while (temp->right != NULL) {
temp = temp->right;
}
// Connect the right subtree to the rightmost node of the left subtree
temp->right = root->right;

// Move the left subtree to the right


root->right = root->left;
root->left = NULL; // Set the left child to NULL
}
// Recursively flatten the right subtree (this will now be a linked list)
flatten(root->right);
}
// Helper function to print the flattened tree in pre-order
void printFlattened(struct TreeNode* root) {
while (root != NULL) {
printf("%d ", root->val);
root = root->right; // Move to the next node in the "linked list"
}
printf("\n");
}
// Function to create a new TreeNode
struct TreeNode* newNode(int val) {
struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
node->val = val;
node->left = node->right = NULL;
return node;
}
int Main() {
// Construct the tree: root = [1,2,5,3,4,null,6]
struct TreeNode* root = newNode(1);
root->left = newNode(2);
root->left->left = newNode(3);
root->left->left->left = newNode(4);
root->right = newNode(5);
root->right->right = newNode(6);
// Flatten the tree
flatten(root);
// Print the flattened tree
printFlattened(root); // Expected output: 1 2 3 4 5 6
return 0;
}

54
55
Program 4:
Given the root of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to
right, level by level).

Solution:
#include <stdio.h>
#include <stdlib.h>
struct treeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
};
// Definition for a Queue
struct Queue {
struct TreeNode** data;
int front, rear, size, capacity;
};
// Function to create a new Queue
struct Queue* createQueue(int capacity) {
struct Queue* queue = (struct Queue*)malloc(sizeof(struct Queue));
queue->capacity = capacity;
queue->size = 0;
queue->front = 0;
queue->rear = -1;
queue->data = (struct TreeNode**)malloc(sizeof(struct TreeNode*) * capacity);
return queue;
}
// Function to check if the Queue is empty
int isQueueEmpty(struct Queue* queue) {
return (queue->size == 0);
}
// Function to enqueue an element into the Queue
void enqueue(struct Queue* queue, struct TreeNode* node) {
if (queue->size == queue->capacity) {
printf("Queue is full\n");
return;
}
queue->rear = (queue->rear + 1) % queue->capacity;
queue->data[queue->rear] = node;
queue->size++;
}
// Function to dequeue an element from the Queue
struct TreeNode* dequeue(struct Queue* queue) {
if (isQueueEmpty(queue)) {
printf("Queue is empty\n");
return NULL;
}
struct TreeNode* node = queue->data[queue->front];
queue->front = (queue->front + 1) % queue->capacity;
queue->size--;
return node;
}

56
// Function to create a new TreeNode
struct TreeNode* newNode(int val) {
struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
node->val = val;
node->left = node->right = NULL;
return node;
}
// Function to perform level order traversal
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes) {
if (root == NULL) {
*returnSize = 0;
return NULL;
}
struct Queue* queue = createQueue(2000);
enqueue(queue, root);
int** result = (int**)malloc(sizeof(int*) * 2000); // To store the level order traversal
*returnColumnSizes = (int*)malloc(sizeof(int) * 2000);
*returnSize = 0;
while (!isQueueEmpty(queue)) {
int levelSize = queue->size;
result[*returnSize] = (int*)malloc(sizeof(int) * levelSize);
(*returnColumnSizes)[*returnSize] = levelSize;
for (int i = 0; i < levelSize; i++) {
struct TreeNode* node = dequeue(queue);
result[*returnSize][i] = node->val;
if (node->left) enqueue(queue, node->left);
if (node->right) enqueue(queue, node->right);
}
(*returnSize)++;
}
return result;
}
// Function to print the result
void printLevelOrder(int** result, int returnSize, int* returnColumnSizes) {
for (int i = 0; i < returnSize; i++) {
printf("[");
for (int j = 0; j < returnColumnSizes[i]; j++) {
printf("%d", result[i][j]);
if (j < returnColumnSizes[i] - 1) {
printf(",");
}
}
printf("]\n");
}
}
int Main() {
// Construct the tree: root = [3, 9, 20, null, null, 15, 7]
struct TreeNode* root = newNode(3);
root->left = newNode(9);
root->right = newNode(20);
root->right->left = newNode(15);

57
root->right->right = newNode(7);
// Perform level order traversal
int returnSize = 0;
int* returnColumnSizes = NULL;
int** result = levelOrder(root, &returnSize, &returnColumnSizes);
// Print the result
printLevelOrder(result, returnSize, returnColumnSizes);
return 0;
}

58
Program 5:
Serialization is the process of converting a data structure or object into a sequence of bits so that it
can be stored in a file or memory buffer, or transmitted across a network connection link to be
reconstructed later in the same or another computer environment.
Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your
serialization/deserialization algorithm should work. You just need to ensure that a binary tree can
be serialized to a string and this string can be deserialized to the original tree structure.
Clarification: The input/output format is the same as how LeetCode serializes a binary tree. You
do not necessarily need to follow this format, so please be creative and come up with different
approaches yourself.
Solution:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Definition for a binary tree node.
struct treeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
};
// Function to create a new node
struct TreeNode* newNode(int val) {
struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
node->val = val;
node->left = NULL;
node->right = NULL;
return node;
}
// Function to serialize a binary tree
char* serialize(struct TreeNode* root) {
// Allocate a large enough buffer for serialized data
char* result = (char*)malloc(10000 * sizeof(char));
int pos = 0;
// Helper function for preorder traversal to populate the result
void serializeHelper(struct TreeNode* node) {
if (node == NULL) {
// If node is null, append "null"
pos += sprintf(result + pos, "null,");
return;
}
// Append the node value and a comma
pos += sprintf(result + pos, "%d,", node->val);
// Recursively serialize left and right children
serializeHelper(node->left);
serializeHelper(node->right);
}
serializeHelper(root);
// Remove the last comma
result[pos - 1] = '\0';
return result;
}
// Function to deserialize a string to reconstruct the binary tree

59
struct TreeNode* deserialize(char* data) {
// Helper function to recursively build the tree
struct TreeNode* deserializeHelper(char** data) {
if (data == NULL || *data == NULL || **data == '\0') {
return NULL;
}
// Read the next value in the data string
char* valStr = *data;
char* commaPos = strchr(valStr, ',');
if (commaPos != NULL) {
*commaPos = '\0'; // Separate the value from the comma
*data = commaPos + 1;
}
if (strcmp(valStr, "null") == 0) {
return NULL;
}
// Otherwise, convert the value to an integer and create a new node
struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
node->val = atoi(valStr);
// Recursively build left and right subtrees
node->left = deserializeHelper(data);
node->right = deserializeHelper(data);
return node;
}

return deserializeHelper(&data);
}
// Function to print the tree (used for testing)
void printTree(struct TreeNode* root) {
if (root == NULL) {
printf("null ");
return;
}
printf("%d ", root->val);
printTree(root->left);
printTree(root->right);
}

int Main() {
// Example: root = [1,2,3,null,null,4,5]
struct TreeNode* root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->right->left = newNode(4);
root->right->right = newNode(5);
// Serialize the tree
char* serialized = serialize(root);
printf("Serialized: %s\n", serialized);
// Deserialize the string back to a tree
struct TreeNode* deserialized = deserialize(serialized);
// Print the deserialized tree
printf("Deserialized: ");

60
printTree(deserialized);
free(serialized);
return 0;
}

61
GRAPHS
Program 1:
There are a total of numCourses courses you have to take, labeled from 0 to numCourses - 1. You
are given an array prerequisites where prerequisites[i] = [ai, bi] indicates that you must take
course bi first if you want to take course ai.
• For example, the pair [0, 1], indicates that to take course 0 you have to first take course 1.
Return true if you can finish all courses. Otherwise, return false.
Solution:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define UNVISITED 0
#define VISITING 1
#define VISITED 2
bool dfs(int node, int *state, int **graph, int numCourses) {
// If the node is in the current recursion stack (VISITING), there's a cycle
if (state[node] == VISITING) {
return false;
}
// If the node has been fully visited, no need to explore it again
if (state[node] == VISITED) {
return true;
}
// Mark the node as visiting (part of the current path)
state[node] = VISITING;
// Explore all neighbors (i.e., courses that depend on the current course)
for (int i = 0; i < numCourses; i++) {
if (graph[node][i] == 1 && !dfs(i, state, graph, numCourses)) {
return false;
}
}
// Mark the node as visited after exploring all neighbors
state[node] = VISITED;
return true;
}
bool canFinish(int numCourses, int** prerequisites, int prerequisitesSize, int* prerequisitesColSize)
{
// Create the adjacency matrix for the graph
int **graph = (int **)malloc(numCourses * sizeof(int *));
for (int i = 0; i < numCourses; i++) {
graph[i] = (int *)calloc(numCourses, sizeof(int)); // Initialize all elements to 0
}
// Fill the adjacency matrix with the prerequisites information
for (int i = 0; i < prerequisitesSize; i++) {
int course = prerequisites[i][0];
int prereq = prerequisites[i][1];
graph[prereq][course] = 1; // There's a directed edge from prereq to course
}
// Create a state array to track the status of each node
int *state = (int *)malloc(numCourses * sizeof(int));

62
for (int i = 0; i < numCourses; i++) {
state[i] = UNVISITED;
}
// Perform DFS for every course to check for cycles
for (int i = 0; i < numCourses; i++) {
if (state[i] == UNVISITED) {
if (!dfs(i, state, graph, numCourses)) {
free(state);
for (int i = 0; i < numCourses; i++) {
free(graph[i]);
}
free(graph);
return false; // A cycle is found, cannot finish all courses
}
}
}

// Free allocated memory


free(state);
for (int i = 0; i < numCourses; i++) {
free(graph[i]);
}
free(graph);
return true; // No cycles found, can finish all courses
}
int Main() {
int prerequisites1[][2] = {{1, 0}};
int prerequisites2[][2] = {{1, 0}, {0, 1}};
int numCourses1 = 2;
int numCourses2 = 2;
int prerequisitesSize1 = 1;
int prerequisitesSize2 = 2;
int prerequisitesColSize1[] = {2};
int prerequisitesColSize2[] = {2, 2};
printf("%d\n", canFinish(numCourses1, (int **)prerequisites1, prerequisitesSize1,
prerequisitesColSize1)); // Should return true
printf("%d\n", canFinish(numCourses2, (int **)prerequisites2, prerequisitesSize2,
prerequisitesColSize2)); // Should return false
return 0;
}

63
Program 2:
In this problem, a tree is an undirected graph that is connected and has no cycles.
You are given a graph that started as a tree with n nodes labeled from 1 to n, with one additional
edge added. The added edge has two different vertices chosen from 1 to n, and was not an edge
that already existed. The graph is represented as an array edges of length n where edges[i] = [ai,
bi] indicates that there is an edge between nodes ai and bi in the graph.
Return an edge that can be removed so that the resulting graph is a tree of n nodes. If there are
multiple answers, return the answer that occurs last in the input.
Solution:
#include <stdio.h>

// Union-Find data structure with path compression and union by rank


typedef struct {
int *parent;
int *rank;
int n;
64
} UnionFind;
// Initialize the Union-Find structure
UnionFind* initUF(int n) {
UnionFind *uf = (UnionFind*)malloc(sizeof(UnionFind));
uf->parent = (int*)malloc(n * sizeof(int));
uf->rank = (int*)malloc(n * sizeof(int));
uf->n = n;
for (int i = 0; i < n; i++) {
uf->parent[i] = i; // Each node is its own parent initially
uf->rank[i] = 0; // Initial rank is 0
}
return uf;
}
// Find the root of a node with path compression
int find(UnionFind *uf, int x) {
if (uf->parent[x] != x) {
uf->parent[x] = find(uf, uf->parent[x]); // Path compression
}
return uf->parent[x];
}
// Union of two sets by rank
void unionSets(UnionFind *uf, int x, int y) {
int rootX = find(uf, x);
int rootY = find(uf, y);
if (rootX != rootY) {
// Union by rank: attach smaller tree under root of larger tree
if (uf->rank[rootX] > uf->rank[rootY]) {
uf->parent[rootY] = rootX;
} else if (uf->rank[rootX] < uf->rank[rootY]) {
uf->parent[rootX] = rootY;
} else {
uf->parent[rootY] = rootX;
uf->rank[rootX]++; // Increase rank if both trees are of equal rank
}
}
}
// Function to find the edge to remove
int* findRedundantConnection(int** edges, int edgesSize, int* edgesColSize, int* returnSize) {
UnionFind *uf = initUF(edgesSize + 1); // Initialize Union-Find for n nodes
int* result = (int*)malloc(2 * sizeof(int));
*returnSize = 2; // The result array will have two elements (the edge to remove)
for (int i = 0; i < edgesSize; i++) {
int u = edges[i][0] - 1; // Adjust for 0-indexing
int v = edges[i][1] - 1; // Adjust for 0-indexing
// If u and v are already connected, then this edge creates a cycle
if (find(uf, u) == find(uf, v)) {
result[0] = edges[i][0]; // Store the edge
result[1] = edges[i][1]; // Store the edge
} else {
// Otherwise, union the nodes
unionSets(uf, u, v);
}

65
}
return result;
}
int Main() {
int edges1[3][2] = {{1, 2}, {1, 3}, {2, 3}};
int *edges1Ptrs[3] = {edges1[0], edges1[1], edges1[2]};
int returnSize1;
int* result1 = findRedundantConnection(edges1Ptrs, 3, (int[]){2, 2, 2}, &returnSize1);
printf("Redundant edge: [%d, %d]\n", result1[0], result1[1]); // Expected: [2, 3]
int edges2[4][2] = {{1, 2}, {2, 3}, {3, 4}, {1, 4}, {1, 5}};
int *edges2Ptrs[4] = {edges2[0], edges2[1], edges2[2], edges2[3]};
int returnSize2;
int* result2 = findRedundantConnection(edges2Ptrs, 5, (int[]){2, 2, 2, 2, 2}, &returnSize2);
printf("Redundant edge: [%d, %d]\n", result2[0], result2[1]); // Expected: [1, 4]

return 0;
}

66
Program 3:
You are given an array of strings equations that represent relationships between variables where
each string equations[i] is of length 4 and takes one of two different
forms: "xi==yi" or "xi!=yi".Here, xi and yi are lowercase letters (not necessarily different) that
represent one-letter variable names.
Return true if it is possible to assign integers to variable names so as to satisfy all the given
equations, or false otherwise.
Solution:
#include <stdio.h>
#include <stdbool.h>
#define ALPHABET_SIZE 26
// Union-Find (Disjoint Set Union) structure
typedef struct {
int parent[ALPHABET_SIZE]; // Parent of each node
int rank[ALPHABET_SIZE]; // Rank (used for union by rank)
} UnionFind;
// Initialize the Union-Find structure
void initUF(UnionFind* uf) {
for (int i = 0; i < ALPHABET_SIZE; i++) {
uf->parent[i] = i; // Initially, each node is its own parent
uf->rank[i] = 0; // Initially, rank is 0
}
}
// Find the root of a node with path compression
int find(UnionFind* uf, int x) {
if (uf->parent[x] != x) {
uf->parent[x] = find(uf, uf->parent[x]); // Path compression
}
return uf->parent[x];
}
// Union of two sets by rank
void unionSets(UnionFind* uf, int x, int y) {
int rootX = find(uf, x);
int rootY = find(uf, y);
if (rootX != rootY) {
// Union by rank: attach smaller tree under root of larger tree
if (uf->rank[rootX] > uf->rank[rootY]) {
uf->parent[rootY] = rootX;
} else if (uf->rank[rootX] < uf->rank[rootY]) {
uf->parent[rootX] = rootY;
} else {
uf->parent[rootY] = rootX;
uf->rank[rootX]++; // Increase rank if both trees are of equal rank
}
}
}
// Convert character to index (0 for 'a', 1 for 'b', ..., 25 for 'z')
int charToIndex(char c) {
return c - 'a';
}
// Function to check if the equations are satisfiable
bool equationsPossible(char** equations, int equationsSize) {

67
UnionFind uf;
initUF(&uf);
// First pass: Process all "=="
for (int i = 0; i < equationsSize; i++) {
if (equations[i][1] == '=') {
int x = charToIndex(equations[i][0]);
int y = charToIndex(equations[i][3]);
unionSets(&uf, x, y);
}
}
// Second pass: Process all "!=" and check if any are violated
for (int i = 0; i < equationsSize; i++) {
if (equations[i][1] == '!') {
int x = charToIndex(equations[i][0]);
int y = charToIndex(equations[i][3]);
if (find(&uf, x) == find(&uf, y)) {
return false; // Violation of inequality
}
}
}
return true;
}

// Test the function


int Main() {
char* equations1[] = {"a==b", "b!=a"};
printf("Output: %s\n", equationsPossible(equations1, 2) ? "true" : "false"); // Expected: false
char* equations2[] = {"b==a", "a==b"};
printf("Output: %s\n", equationsPossible(equations2, 2) ? "true" : "false"); // Expected: true
return 0;
}

68
Program 4:
You have n gardens, labeled from 1 to n, and an array paths where paths[i] = [xi, yi] describes a
bidirectional path between garden xi to garden yi. In each garden, you want to plant one of 4 types
of flowers.
All gardens have at most 3 paths coming into or leaving it.
Your task is to choose a flower type for each garden such that, for any two gardens connected by a
path, they have different types of flowers.
Return any such a choice as an array answer, where answer[i] is the type of flower planted in
the (i+1)th garden. The flower types are denoted 1, 2, 3, or 4. It is guaranteed an answer exists.
Solution:
#include <stdio.h>
#include <stdlib.h>
#define MAX_GARDENS 10000
#define MAX_FLOWER_TYPES 4
// Function to find the minimum flower type available
int getAvailableFlower(int *colors, int garden, int *adjList[], int adjSize[]) {
int used[5] = {0}; // Array to track which flower types are used by neighbors (1-indexed)
// Check all neighbors and mark their flower types as used
for (int i = 0; i < adjSize[garden]; i++) {
int neighbor = adjList[garden][i];
if (colors[neighbor] != 0) {
used[colors[neighbor]] = 1;
}
}
// Find the smallest flower type that is not used
for (int i = 1; i <= MAX_FLOWER_TYPES; i++) {
if (used[i] == 0) {
return i;
}
}
return -1; // This should never happen since we have at most 4 neighbors
}

// Function to solve the problem


int* gardenNoAdj(int n, int** paths, int pathsSize, int* pathsColSize, int* returnSize) {
int *adjList[MAX_GARDENS];
69
int adjSize[MAX_GARDENS] = {0}; // To store the size of each adjacency list
// Initialize adjacency lists
for (int i = 0; i < MAX_GARDENS; i++) {
adjList[i] = (int*)malloc(MAX_GARDENS * sizeof(int));
}
// Construct the graph (adjacency list)
for (int i = 0; i < pathsSize; i++) {
int x = paths[i][0] - 1; // Convert 1-based index to 0-based
int y = paths[i][1] - 1; // Convert 1-based index to 0-based
adjList[x][adjSize[x]++] = y;
adjList[y][adjSize[y]++] = x;
}
// Array to store the colors (flower types)
int *colors = (int*)malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
colors[i] = 0; // 0 means no flower assigned yet
}
// Assign flowers to gardens
for (int i = 0; i < n; i++) {
colors[i] = getAvailableFlower(colors, i, adjList, adjSize);
}
*returnSize = n;
return colors;
}
// Main function to test
int Main() {
// Test case 1: Input: n = 3, paths = [[1,2],[2,3],[3,1]]
int paths1[3][2] = {{1, 2}, {2, 3}, {3, 1}};
int *pathPtrs1[3];
for (int i = 0; i < 3; i++) {
pathPtrs1[i] = paths1[i];
}
int returnSize1;
int *result1 = gardenNoAdj(3, pathPtrs1, 3, NULL, &returnSize1);
printf("Test case 1 result: ");
for (int i = 0; i < returnSize1; i++) {
printf("%d ", result1[i]);
}
printf("\n");
// Test case 2: Input: n = 4, paths = [[1,2],[3,4]]
int paths2[2][2] = {{1, 2}, {3, 4}};
int *pathPtrs2[2];
for (int i = 0; i < 2; i++) {
pathPtrs2[i] = paths2[i];
}
int returnSize2;
int *result2 = gardenNoAdj(4, pathPtrs2, 2, NULL, &returnSize2);
printf("Test case 2 result: ");
for (int i = 0; i < returnSize2; i++) {
printf("%d ", result2[i]);
}
printf("\n");

70
// Clean up memory
free(result1);
free(result2);

return 0;
}

71
Program 5:
You are given a tree (i.e. a connected, undirected graph that has no cycles) rooted at
node 0 consisting of n nodes numbered from 0 to n - 1. The tree is represented by a 0-
indexed array parent of size n, where parent[i] is the parent of node i. Since node 0 is the
root, parent[0] == -1.
You are also given a string s of length n, where s[i] is the character assigned to node i.
Return the length of the longest path in the tree such that no pair of adjacent nodes on the path
have the same character assigned to them.
Solution:
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
Solution:
class Solution {
public:
int longestPath(vector<int>& parent, string& s) {
int n = parent.size();
// Step 1: Build the tree using adjacency list
vector<vector<int>> tree(n);
for (int i = 1; i < n; ++i) {
tree[parent[i]].push_back(i);
}
// Step 2: DFS helper function to find longest path
int result = 1; // We always have at least one node in the path (itself)

function<int(int)> dfs = [&](int node) -> int {


int firstMax = 0, secondMax = 0; // Keep track of the two longest paths
for (int child : tree[node]) {
int childPath = dfs(child); // Get longest path for this child
// If the character of the child node is different from the current node
if (s[child] != s[node]) {
if (childPath > firstMax) {
72
secondMax = firstMax; // Update secondMax
firstMax = childPath; // Update firstMax
} else if (childPath > secondMax) {
secondMax = childPath; // Update secondMax
}
}
}
// Update result, we can form a path with current node and its two longest valid children paths
result = max(result, firstMax + secondMax + 1);
// Return the longest path from this node to its child
return firstMax + 1;
};
// Start DFS from the root (node 0)
dfs(0);
// The result is stored in the variable `result`
return result;
}
};

73
74

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy