1. Array & String
1) Merge sorted array
You are given two integer arrays nums1 and nums2, sorted in non-decreasing order, and two integers m and n, representing the number of elements in nums1 and nums2 respectively.
Merge nums1 and nums2 into a single array sorted in non-decreasing order.
The final sorted array should not be returned by the function, but instead be stored inside the array nums1. To accommodate this, nums1 has a length of m + n, where the first m elements denote the elements that should be merged, and the last n elements are set to 0 and should be ignored. nums2 has a length of n.
Example 1:
Input: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
Output: [1,2,2,3,5,6]
Explanation: The arrays we are merging are [1,2,3] and [2,5,6].
The result of the merge is [1,2,2,3,5,6] with the underlined elements coming from nums1.
Solution:
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
int i = m - 1; // Index for nums1
int j = n - 1; // Index for nums2
int k = m + n - 1; // Index faor merged array
// Merge arrays from the end
while (i >= 0 && j >= 0) {
if (nums1[i] > nums2[j]) {
nums1[k] = nums1[i];
i--;
} else {
nums1[k] = nums2[j];
j--;
}
k--;
}
// If there are remaining elements in nums2, copy them to nums1
while (j >= 0) {
nums1[k] = nums2[j];
j--;
k--;
}
}
2) Remove Element
Given an integer array nums and an integer val, remove all occurrences of val in nums in-place. The order of the elements may be changed. Then return the number of elements in nums which are not equal to val.
Consider the number of elements in nums which are not equal to val be k, to get accepted, you need to do the following things:
Change the array nums such that the first k elements of nums contain the elements which are not equal to val. The remaining elements of nums are not important as well as the size of nums. Return k.
Example 1:
Input: nums = [3,2,2,3], val = 3
Output: 2, nums = [2,2,_,_]
Explanation: Your function should return k = 2, with the first two elements of nums being 2.
It does not matter what you leave beyond the returned k (hence they are underscores).
Solution:
int removeElement(int* nums, int numsSize, int val) {
int k = 0; // Counter for elements not equal to val
for (int i = 0; i < numsSize; i++) {
if (nums[i] != val) {
nums[k] = nums[i];
k++;
}
}
return k;
}
3) Remove Duplicates from Sorted Array
Given an integer array nums sorted in non-decreasing order, remove the duplicates in-place such that each unique element appears *only once*. The relative order of the elements should be kept the same. Then return the number of unique elements in nums.
Consider the number of unique elements of nums to be k, to get accepted, you need to do the following things:
Change the array nums such that the first k elements of nums contain the unique elements in the order they were present in nums initially. The remaining elements of nums are not important as well as the size of nums. Return k.
Example 1:
Input: nums = [0,0,1,1,1,2,2,3,3,4]
Output: 5, nums = [0,1,2,3,4,_,_,_,_,_]
Explanation: Your function should return k = 5, with the first five elements of nums being 0, 1, 2, 3, and 4 respectively.
It does not matter what you leave beyond the returned k (hence they are underscores).
Solution:
int removeDuplicates(int* nums, int numsSize) {
int k = 1;
for (int i = 1; i < numsSize; i++) {
if (nums[i] > nums[i-1]) {
nums[k] = nums[i];
k++;
}
}
return k;
}
4) Remove Duplicates from Sorted Array II
Given an integer array nums sorted in non-decreasing order, remove some duplicates in-place such that each unique element appears *at most twice*. The relative order of the elements should be kept the same.
Since it is impossible to change the length of the array in some languages, you must instead have the result be placed in the first part of the array nums. More formally, if there are k elements after removing the duplicates, then the first k elements of nums should hold the final result. It does not matter what you leave beyond the first k elements.
Return k after placing the final result in the first k slots of nums.
Do not allocate extra space for another array. You must do this by modifying the input array in-place with O(1) extra memory.
Example 1:
Input: nums = [1,1,1,2,2,3]
Output: 5, nums = [1,1,2,2,3,_]
Solution:
int removeDuplicates(int* nums, int numsSize) {
if (numsSize <= 2)
return numsSize;
int k = 2;
for (int i = 2; i < numsSize; i++) {
if (nums[i] > nums[k-2]) {
nums[k] = nums[i];
k++;
}
}
return k;
}
5) Majority Element
Given an array nums of size n, return the majority element.
The majority element is the element that appears more than n / 2 times. You may assume that the majority element always exists in the array.
Example 1:
Input: nums = [2,2,1,1,1,2,2]
Output: 2
Solution:
int majorityElement(int* nums, int numsSize) {
int candidate = nums[0];
int count = 1;
for (int i = 1; i < numsSize; i++) {
if (count == 0) {
candidate = nums[i];
count = 1;
} else if (nums[i] == candidate) {
count++;
} else {
count--;
}
}
return candidate;
}
6) Rotate Array
Given an integer array nums, rotate the array to the right by k steps, where k is non-negative.
Example 1:
Input: nums = [1,2,3,4,5,6,7], k = 3
Output: [5,6,7,1,2,3,4]
Explanation:
rotate 1 steps to the right: [7,1,2,3,4,5,6]
rotate 2 steps to the right: [6,7,1,2,3,4,5]
rotate 3 steps to the right: [5,6,7,1,2,3,4]
Solution:
void rotate(int* nums, int numsSize, int k) {
// 处理 k 大于数组长度的情况
k = k % numsSize;
// 创建一个临时数组来存储旋转后的结果
int temp[numsSize];
// 将原数组的元素复制到临时数组,同时完成旋转
for (int i = 0; i < numsSize; i++) {
temp[(i + k) % numsSize] = nums[i];
}
// 将临时数组的内容复制回原数组
for (int i = 0; i < numsSize; i++) {
nums[i] = temp[i];
}
}
7) Roman to Integar
Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.
Symbol Value
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
For example, 2 is written as II in Roman numeral, just two ones added together. 12 is written as XII, which is simply X + II. The number 27 is written as XXVII, which is XX + V + II.
Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:
I can be placed before V (5) and X (10) to make 4 and 9.
X can be placed before L (50) and C (100) to make 40 and 90.
C can be placed before D (500) and M (1000) to make 400 and 900.
Given a roman numeral, convert it to an integer.
Example 1:
Input: s = "LVIII"
Output: 58
Explanation: L = 50, V= 5, III = 3.
Solution:
int romanToInt(char* s) {
int values[26];
values['I' - 'A'] = 1;
values['V' - 'A'] = 5;
values['X' - 'A'] = 10;
values['L' - 'A'] = 50;
values['C' - 'A'] = 100;
values['D' - 'A'] = 500;
values['M' - 'A'] = 1000;
int result = 0;
int prevValue = 0;
for (int i = strlen(s) - 1; i >= 0; i--) {
int currentValue = values[s[i] - 'A'];
if (currentValue >= prevValue) {
result += currentValue;
} else {
result -= currentValue;
}
prevValue = currentValue;
}
return result;
}
8) Length of Last Word
Given a string s consisting of words and spaces, return the length of the last word in the string.
A word is a maximal substring consisting of non-space characters only.
Example 1:
Input: s = " fly me to the moon "
Output: 4
Explanation: The last word is "moon" with length 4.
Solution:
int lengthOfLastWord(char* s) {
int length = 0;
int i = strlen(s) - 1;
// Skip trailing spaces
while (i >= 0 && s[i] == ' ') {
i--;
}
// Count characters of the last word
while (i >= 0 && s[i] != ' ') {
length++;
i--;
}
return length;
}
9) Find the index of the first occurance in a string
Given two strings needle and haystack, return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
Example 1:
Input: haystack = "sadbutsad", needle = "sad"
Output: 0
Explanation: "sad" occurs at index 0 and 6.
The first occurrence is at index 0, so we return 0.
Solution:
#include <string.h>
int strStr(char* haystack, char* needle) {
char* result = strstr(haystack, needle);
if (result == NULL) {
return -1;
} else {
return result - haystack;
}
}
10) Longest Common Prefix
Write a function to find the longest common prefix string amongst an array of strings.
If there is no common prefix, return an empty string "".
Example 1:
Input: strs = ["flower","flow","flight"]
Output: "fl"
Example 2:
Input: strs = ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix among the input strings.
Solution:
char* longestCommonPrefix(char** strs, int strsSize) {
char* prefix = (char*)malloc(201 * sizeof(char));
prefix[0] = '\0';
if (strsSize == 0)
return "";
int k = 0;
// matching from first character of strs[0] till end of it
while (strs[0][k] != '\0') {
// current is the char to be compared
char current = strs[0][k];
// go through following strings in the array
for (int i = 1; i < strsSize; i++) {
// if the letter does not match with the one in strs[0], or if end
// of string is reached
if (strs[i][k] != current || strs[i][k] == '\0') {
// add '\0' to prefix[] and return
prefix[k] = '\0';
return prefix;
}
}
prefix[k] = current;
k++;
}
// append end of string to prefix[]
prefix[k] = '\0';
return prefix;
}
11) Best Time to Buy and Sell Stock
You are given an array prices where prices[i] is the price of a given stock on the ith day.
You want to maximize your profit by choosing a single day to buy one stock and choosing a different day in the future to sell that stock.
Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return 0.
Example 1:
Input: prices = [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell.
Example 2:
Input: prices = [7,6,4,3,1]
Output: 0
Explanation: In this case, no transactions are done and the max profit = 0.
Solution 1: O(n2)
int maxProfit(int* prices, int pricesSize) {
int max_profit = 0;
// i = buy date, j = sell date.
for (int i = 0; i < (pricesSize - 1); i++) {
for (int j = i + 1; j < pricesSize; j++) {
// if there's higher profit, update max_profit.
if (prices[j] > prices[i]) {
max_profit = max_profit < (prices[j] - prices[i]) ? (prices[j] - prices[i]) : max_profit;
}
}
}
return max_profit;
}
Solution 2: O(n)
int maxProfit(int* prices, int pricesSize) {
// minPrice to track lowest price
int minPrice = prices[0];
int maxProfit = 0;
// if array size < 2, return 0.
if(pricesSize < 2) {
return 0;
}
// interating through prices
for (int i = 1; i < pricesSize; i++) {
// update maxProfit if higher value found
if( (prices[i] - minPrice) > maxProfit) {
maxProfit = prices[i] - minPrice;
}
// update minPrice if lower price found
if (prices[i] < minPrice) {
minPrice = prices[i];
}
}
return maxProfit;
}
2. Pointers
1) Valid Palindrome
A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters include letters and numbers.
Given a string s, return true if it is a palindrome, or false otherwise.
Example 1:
Input: s = "A man, a plan, a canal: Panama"
Output: true
Explanation: "amanaplanacanalpanama" is a palindrome.
Solution:
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
bool isPalindrome(char* s) {
int length = strlen(s);
char tmp[length + 1]; // +1 for null terminator
int k = 0;
for (int i = 0; i < length; i++) {
if ('A' <= s[i] && s[i] <= 'Z')
tmp[k++] = s[i] + ('a' - 'A');
else if (('a' <= s[i] && s[i] <= 'z') || ('0' <= s[i] && s[i] <= '9'))
tmp[k++] = s[i];
}
tmp[k] = '\0';
for (int j = 0; j < k / 2; j++) {
if (tmp[j] != tmp[k-1-j])
return false;
}
return true;
}
2) Is Subsequence
Given two strings s and t, return true if s is a subsequence of t, or false otherwise.
A subsequence of a string is a new string that is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (i.e., "ace" is a subsequence of "abcde" while "aec" is not).
Example 1:
Input: s = "abc", t = "ahbgdc"
Output: true
Solution:
bool isSubsequence(char* s, char* t) {
if (strlen(t) < strlen(s))
return false;
for (int i = 0; i < strlen(s); i++) {
for (int j = i; j < strlen(t); j++) {
if (t[j] == s[i])
break;
if (j == (strlen(t) - 1))
return false;
}
}
return true;
}
Or better:
#include <stdbool.h>
#include <string.h>
bool isSubsequence(char * s, char * t) {
int s_len = strlen(s);
int t_len = strlen(t);
// If s is empty, it's always a subsequence
if (s_len == 0) return true;
int s_index = 0;
// Iterate through t
for (int t_index = 0; t_index < t_len; t_index++) {
// If current characters match, move to next character in s
if (s[s_index] == t[t_index]) {
s_index++;
// If we've matched all characters in s, return true
if (s_index == s_len) return true;
}
}
// If we haven't matched all characters in s, return false
return false;
}
3) Two Sum II - Array is Sorted
Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number. Let these two numbers be numbers[index1] and numbers[index2] where 1 <= index1 < index2 <= numbers.length.
Return the indices of the two numbers, index1 and index2, added by one as an integer array [index1, index2] of length 2.
The tests are generated such that there is exactly one solution. You may not use the same element twice.
Your solution must use only constant extra space.
Example 1:
Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: The sum of 2 and 7 is 9. Therefore, index1 = 1, index2 = 2. We return [1, 2].
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* twoSum(int* numbers, int numbersSize, int target, int* returnSize) {
int left = 0;
int right = numbersSize - 1;
int* result = (int*)malloc(2 * sizeof(int));
*returnSize = 2;
while (left < right) {
int sum = numbers[left] + numbers[right];
if (sum == target) {
result[0] = left + 1; // +1 because the array is 1-indexed
result[1] = right + 1;
return result;
} else if (sum < target) {
left++;
} else {
right--;
}
}
// This line should never be reached if there's guaranteed to be a solution
return result;
}
3. Hashmap
1) Ransom Note
Given two strings ransomNote and magazine, return true if ransomNote can be constructed by using the letters from magazine and false otherwise.
Each letter in magazine can only be used once in ransomNote.
Example 1:
Input: ransomNote = "aa", magazine = "ab"
Output: false
Example 2:
Input: ransomNote = "aa", magazine = "aab"
Output: true
Solution 1:
bool canConstruct(char* ransomNote, char* magazine) {
int ransom_len = strlen(ransomNote), magazine_len = strlen(magazine);
int used[magazine_len];
memset(used, 0, sizeof(used));
for (int i = 0; i < ransom_len; i++) {
bool found = false;
for (int j = 0; j < magazine_len; j++) {
if ((ransomNote[i] == magazine[j]) && (used[j] == 0)) {
used[j] = 1;
found = true;
break;
}
}
if (!found)
return false;
}
return true;
}
Solution 2:
#include <stdbool.h>
bool canConstruct(char* ransomNote, char* magazine) {
int count[26] = {0}; // 假设只有小写字母
// 统计 magazine 中每个字符的出现次数
for (int i = 0; magazine[i]; i++) {
count[magazine[i] - 'a']++;
}
// 检查 ransomNote 中的每个字符
for (int i = 0; ransomNote[i]; i++) {
if (--count[ransomNote[i] - 'a'] < 0) {
return false;
}
}
return true;
}
2) Isomorphic Strings
Given two strings s and t, determine if they are isomorphic.
Two strings s and t are isomorphic if the characters in s can be replaced to get t.
All occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character, but a character may map to itself.
Example 1:
Input: s = "egg", t = "add"
Output: true
Explanation: The strings s and t can be made identical by:
Mapping 'e' to 'a'.
Mapping 'g' to 'd'.
Example 2:
Input: s = "foo", t = "bar"
Output: false
Explanation:
The strings s and t can not be made identical as 'o' needs to be mapped to both 'a' and 'r'.
Example 3:
Input: s = "paper", t = "title"
Output: true
Solution: dual-direction-mapping
#include <string.h>
bool isIsomorphic(char* s, char* t) {
int s_to_t[256] = {0};
int t_to_s[256] = {0};
int length = strlen(s);
for (int i = 0; i < length; i++) {
if (( s_to_t[s[i]] == 0) && (t_to_s[t[i]] == 0)) {
s_to_t[s[i]] = t[i];
t_to_s[t[i]] = s[i];
} else if ((s_to_t[s[i]] != t[i]) || (t_to_s[t[i]] != s[i])) {
return false;
}
}
return true;
}
3) Word Pattern
Given a pattern and a string s, find if s follows the same pattern.
Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty word in s. Specifically:
Each letter in pattern maps to exactly one unique word in s.
Each unique word in s maps to exactly one letter in pattern.
No two letters map to the same word, and no two words map to the same letter.
Example 1:
Input: pattern = "abba", s = "dog cat cat dog"
Output: true
Explanation: The bijection can be established as:
'a' maps to "dog".
'b' maps to "cat".
Example 2:
Input: pattern = "abba", s = "dog cat cat fish"
Output: false
Example 3:
Input: pattern = "aaaa", s = "dog cat cat dog"
Output: false
Solution:
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
bool wordPattern(char* pattern, char* s) {
char* words[26] = {0}; // 存储每个字母对应的单词
char* used_words[100] = {0}; // 存储已使用的单词
int used_count = 0;
int len = strlen(pattern);
char* token = strtok(s, " ");
for (int i = 0; i < len; i++) {
if (token == NULL) {
return false; // 单词数量少于模式长度
}
int index = pattern[i] - 'a';
if (words[index] == NULL) {
// 检查这个单词是否已经被映射到其他字母
for (int j = 0; j < used_count; j++) {
if (strcmp(used_words[j], token) == 0) {
return false;
}
}
words[index] = strdup(token);
used_words[used_count++] = words[index];
} else if (strcmp(words[index], token) != 0) {
return false;
}
token = strtok(NULL, " ");
}
if (token != NULL) {
return false; // 单词数量多于模式长度
}
// 释放分配的内存
for (int i = 0; i < 26; i++) {
free(words[i]);
}
return true;
}
4)
Given two strings s and t, return true if t is an anagram of s, and false otherwise.
Example 1:
Input: s = "anagram", t = "nagaram"
Output: true
Example 2:
Input: s = "rat", t = "car"
Output: false
Constraints:
1 <= s.length, t.length <= 5 * 104
s and t consist of lowercase English letters.
Solution:
bool isAnagram(char* s, char* t) {
int words[26] = {0};
int length_s = strlen(s);
int length_t = strlen(t);
if (length_s != length_t)
return false;
for (int i = 0; i < length_s; i++) {
words[s[i] - 'a']++;
words[t[i] - 'a']--;
}
for (int i = 0; i < 26; i++) {
if (words[i] != 0) {
return false;
}
}
return true;
}
4. Linked List
1) Linked List Cycle
Given head, the head of a linked list, determine if the linked list has a cycle in it.
There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the node that tail's next pointer is connected to. Note that pos is not passed as a parameter.
Return true if there is a cycle in the linked list. Otherwise, return false.
Note: cycle may be at the beginning or end of the single list.
Solution:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
if(!head || !(head->next))
return false;
struct ListNode *slow = head;
struct ListNode *fast = head->next;
while (slow != fast) {
if (!fast || !fast->next)
return false;
slow = slow->next;
fast = fast->next->next;
}
return true;
}
2) Merge Two Sorted List
You are given the heads of two sorted linked lists list1 and list2.
Merge the two lists into one sorted list. The list should be made by splicing together the nodes of the first two lists.
Return the head of the merged linked list.
Constraints:
The number of nodes in both lists is in the range [0, 50].
-100 <= Node.val <= 100
Both list1 and list2 are sorted in non-decreasing order.
Solution:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
// If one of the lists is empty, return the other list
if (list1 == NULL) return list2;
if (list2 == NULL) return list1;
// Create a dummy head for the merged list
struct ListNode dummy;
struct ListNode* current = &dummy;
// Traverse both lists and add the smaller node to the merged list
while (list1 && list2) {
if (list1->val <= list2->val) {
current->next = list1;
list1 = list1->next;
} else {
current->next = list2;
list2 = list2->next;
}
current = current->next;
}
// If any list is not fully traversed, add the remaining nodes
if (list1) current->next = list1;
if (list2) current->next = list2;
// Return the head of the merged list (skip the dummy node)
return dummy.next;
}
3) Reverse the Linked List
Given the head of a singly linked list, reverse the nodes of the list, and return the reversed list.
Example 1:
Input: head = [1,2,3,4,5]
Output: [5,4,3,2,1]
Solution:
typedef struct ListNode {
int val;
struct ListNode *next;
}
struct ListNode *reverseList(struct ListNode* head) {
struct ListNode* prev=NULL;
struct ListNode* current=head;
struct ListNode* next=NULL;
while(current != NULL) {
//store next
next = current->next;
//reverse current pointer to point it to prev
current->next=prev;
//move forward
prev=current;
current=next;
}
return prev;
}
*4) Reverse the Linked List II
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.
Example 1:
Input: head = [1,2,3,4,5], left = 2, right = 4
Output: [1,4,3,2,5]
Constraints:
The number of nodes in the list is n.
1 <= n <= 500
-500 <= Node.val <= 500
1 <= left <= right <= n
Solution:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseBetween(struct ListNode* head, int left, int right) {
if (head == NULL || left == right) return head;
struct ListNode dummy;
dummy.next = head;
struct ListNode* prev = &dummy;
// Move to the node just before the sublist to be reversed
for (int i = 1; i < left; i++) {
prev = prev->next;
}
struct ListNode* start = prev->next;
struct ListNode* then = start->next;
// Reverse the sublist
for (int i = 0; i < right - left; i++) {
start->next = then->next;
then->next = prev->next;
prev->next = then;
then = start->next;
}
return dummy.next;
}
5) Rotate List
Given the head of a linked list, rotate the list to the right by k places.
Example 1:
Input: head = [1,2,3,4,5], k = 2
Output: [4,5,1,2,3]
Example 2:
Input: head = [0,1,2], k = 4
Output: [2,0,1]
The number of nodes in the list is in the range [0, 500].
-100 <= Node.val <= 100
0 <= k <= 2 * 109
Solution:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* rotateRight(struct ListNode* head, int k) {
if(head == NULL || head->next == NULL || k == 0)
return head;
//get the list length and last node
struct ListNode *last=head;
int length = 1;
while (last->next != NULL) {
last = last->next;
length++;
}
//adjust k if it's larger then length
k = k % length;
if(k == 0)
return head;
//make last node point to head
last->next = head;
//find the new last node
struct ListNode* newLastNode=head;
for(int i=0;i<length-k-1;i++) {
newLastNode = newLastNode->next;
}
//break the list
struct ListNode* newHead=newLastNode->next;
newLastNode->next = NULL;
return newHead;
}
6) Remove Linked List Elements
Given the head of a linked list and an integer val, remove all the nodes of the linked list that has Node.val == val, and return the new head.
Example 1:
Input: head = [1,2,6,3,4,5,6], val = 6
Output: [1,2,3,4,5]
Solution:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val) {
// create a dummy node pointing to head
struct ListNode dummy;
dummy.next = head;
// starting curr from head
struct ListNode* curr = &dummy;
// iterating till end of the list
while (curr->next != NULL) {
if (curr->next->val == val) {
// create a temp node pointing to the to-be-freed node
struct ListNode *temp = curr->next;
// move curr to the next node
curr->next = curr->next->next;
// then delete the node with target value
free(temp);
} else {
// if not the target value, move forward
curr = curr->next;
}
}
return dummy.next;
}
7) Odd Even Link List
Given the head of a singly linked list, group all the nodes with odd indices together followed by the nodes with even indices, and return the reordered list.
The first node is considered odd, and the second node is even, and so on.
Note that the relative order inside both the even and odd groups should remain as it was in the input.
You must solve the problem in O(1) extra space complexity and O(n) time complexity.
Example 1:
Input: head = [1,2,3,4,5]
Output: [1,3,5,2,4]
Solution:
5. Bit manipulation
1) Add Binary
Given two binary strings a and b, return their sum as a binary string.
Example 1:
Input: a = "11", b = "1"
Output: "100"
Example 2:
Input: a = "1010", b = "1011"
Output: "10101"
Constraints:
1 <= a.length, b.length <= 104
a and b consist only of '0' or '1' characters.
Each string does not contain leading zeros except for the zero itself.
Solution:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* addBinary(char* a, char* b) {
//convert binary string to long
long num_a = strtol(a, NULL, 2);
long num_b = strtol(b, NULL, 2);
//calculate the sum
long sum = num_a + num_b;
//get the max length of result string
int max_len = (strlen(a) > strlen(b) ? strlen(a) : strlen(b)) + 2;
//malloc for result string
char *result_str = (char *)malloc(max_len);
//snprintf sum number in binary to result_str
snprintf(result_str, max_len, "%lb", sum);
return result_str;
}
2) Reverse Bits
Reverse bits of a given 32 bits unsigned integer.
Note:
Note that in some languages, such as Java, there is no unsigned integer type. In this case, both input and output will be given as a signed integer type. They should not affect your implementation, as the integer's internal binary representation is the same, whether it is signed or unsigned.
In Java, the compiler represents the signed integers using 2's complement notation. Therefore, in Example 2 above, the input represents the signed integer -3 and the output represents the signed integer -1073741825.
Example 1:
Input: n = 00000010100101000001111010011100
Output: 964176192 (00111001011110000010100101000000)
Explanation: The input binary string 00000010100101000001111010011100 represents the unsigned integer 43261596, so return 964176192 which its binary representation is 00111001011110000010100101000000.
Solution:
uint32_t reverseBits(uint32_t n) {
uint32_t result = 0;
for (int i = 0; i < 32; i++) {
result = (result << 1) | (n & 1);
n >>= 1;
}
return result;
}
3) Number of 1 Bits
Given a positive integer n, write a function that returns the number of set bits in its binary representation (also known as the Hamming weight).
Example 1:
Input: n = 11
Output: 3
Explanation: The input binary string 1011 has a total of three set bits.
Solution1:
int hammingWeight(int n) {
if (n <= 0)
return 0;
int count = 0;
char b[33] = {0};
snprintf(b, sizeof(b), "%b", n);
for(int i = 0; i < 33; i++) {
if (b[i] == '1')
count++;
}
return count;
}
Solution2 - Brian Kernighan's Algorithm(布莱恩·克尼汉算法)
int hammingWeight(uint32_t n) {
int count = 0;
while (n) {
n &= (n - 1);
count++;
}
return count;
}
4) Single Number
Given a non-empty array of integers nums, every element appears twice except for one. Find that single one.
You must implement a solution with a linear runtime complexity and use only constant extra space.
Example 1:
Input: nums = [2,2,1]
Output: 1
Solution:
int singleNumber(int* nums, int numsSize) {
int result = 0;
for (int i = 0; i < numsSize; i++) {
result ^= nums[i];
}
return result;
}
5) Write a funciton that swaps the highest bits in each nibble of the byte pointed to by the pointer b.
Example:
bits 1xxx0xxx to 0xxx1xxx, the bits designated by 'x' in the example above should not be swapped.
#include <stdint.h>
void swapBits(uint8_t* b) {
if (b == NULL) {
return; // Handle null pointer
}
uint8_t highBitMask = 0x88; // Binary: 10001000
uint8_t highBits = *b & highBitMask;
uint8_t swappedHighBits = ((highBits & 0x80) >> 3) | ((highBits & 0x08) << 3);
*b = (*b & ~highBitMask) | swappedHighBits;
}
6. Macros
1) #define MIN(x, y) ((x) < (y) ? (x) : (y))
2) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
3) #define MAX(x,y) (((x)>(y))?(x):(y))
4)
#define SQUARE(x) x*x
int a = 5;
printf("%d", SQUARE(a+1));
Output: 11 // 5+1*5+1=11, to make it right, define it as (x)*(x)
5) 如何在宏定义中使用do-while(0)结构,有什么好处?
使用do-while(0)可以将多个语句组合成一个复合语句,从而避免在使用宏时可能出现的错误。
当宏被用在if-else语句中时,do-while(0)可以确保宏展开后的语法正确性。
do-while(0)结构允许在使用宏时在末尾加分号,使其看起来像一个普通的函数调用:
在宏定义中,do-while(0)提供了一个可以使用break语句跳出的块,这在某些情况下很有用
对于可能为空的宏定义,使用do-while(0)可以避免编译器产生警告
6) debug below macro, and fix it:
#define MULTIPLY(a,b) a*b
int x = MULTIPLY(3+2, 4+5);
use (a)*(b).
7) Linux内核中常见且具有代表性的宏定义:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0)
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \ //在编译时进行类型检查
_min1 < _min2 ? _min1 : _min2; })
7. debug below function to compute the square of x-pointed value:
uint8_t square(uint8_t *x) {
uint16_t ret = *x * *x;
return ret;
}
==>
#include <stdint.h>
uint16_t square(uint8_t *x) {
if (x == NULL) {
return 0; // 处理空指针情况
}
uint16_t ret = (uint16_t)(*x) * (*x);
return ret;
}
8. Binary Search
Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You must write an algorithm with O(log n) runtime complexity.
Example 1:
Input: nums = [1,3,5,6], target = 5
Output: 2
Example 2:
Input: nums = [1,3,5,6], target = 2
Output: 1
Solution:
int searchInsert(int* nums, int numsSize, int target) {
int left = 0, right = numsSize - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid; // target found
} else if (nums[mid] < target) {
left = mid + 1; // target is at right side
} else {
right = mid - 1; // target is at left side
}
}
// target not found, return the insertion position
return left;
}
9. Math
1) Given an integer x, return true if x is a palindrome, and false otherwise.
Example 1:
Input: x = 121
Output: true
Explanation: 121 reads as 121 from left to right and from right to left.
Example 2:
Input: x = -121
Output: false
Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.
Solution 1: convert integar to string then compare
bool isPalindrome(int x) {
char str[100] = "";
snprintf(str,sizeof(str), "%d", x);
int length = strlen(str);
for (int i = 0; i < (length / 2); i++) {
// if "x" is negative, or asymmetric
if ((str[i] == "-") || (str[i] != str[length - i - 1])) {
return false;
}
}
return true;
}
Solution 2: without converting integer to string
bool isPalindrome(int x) {
// negatives are not palindrome
if (x < 0) return false;
// single digit positive integar is palindrome
if (x < 10) return true;
int div = 1;
// get the highest power of 10
while ((x / div) >= 10) {
div *= 10;
}
// iterating through
while (x > 0) {
// get the left and right most number
int left = x / div;
int right = x % 10;
if(left != right) {
return false;
}
// remove the leftmost and rightmost digits
x = (x % div) / 10;
div /= 100;
}
return true;
}
2) Plus One
You are given a large integer represented as an integer array digits, where each digits[i] is the ith digit of the integer. The digits are ordered from most significant to least significant in left-to-right order. The large integer does not contain any leading 0's.
Increment the large integer by one and return the resulting array of digits.
Example 1:
Input: digits = [1,2,3]
Output: [1,2,4]
Explanation: The array represents the integer 123.
Incrementing by one gives 123 + 1 = 124.
Thus, the result should be [1,2,4].
Example 2:
Input: digits = [4,3,2,1]
Output: [4,3,2,2]
Explanation: The array represents the integer 4321.
Incrementing by one gives 4321 + 1 = 4322.
Thus, the result should be [4,3,2,2].
Example 3:
Input: digits = [9]
Output: [1,0]
Explanation: The array represents the integer 9.
Incrementing by one gives 9 + 1 = 10.
Thus, the result should be [1,0].
Constraints:
1 <= digits.length <= 100
0 <= digits[i] <= 9
digits does not contain any leading 0's.
Solution:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* plusOne(int* digits, int digitsSize, int* returnSize) {
int i = 0;
// start from least siginicant bit
for(i = digitsSize - 1; i >= 0; i--) {
// if the digit < 9, increase it by 1, size of result remains unchanged.
if(digits[i] < 9) {
digits[i] += 1;
*returnSize = digitsSize;
return digits;
}
// if any digit = 9, then increase it by 1 changing the bit to 0.
digits[i] = 0;
}
// if we come here, means every digit was 9.
int *result = (int *)malloc((digitsSize + 1) * sizeof(int));
// highest digit is 1, rest of digits must be 0.
result[0] = 1;
for (i = 1; i <= digitsSize; i++) {
result[i] = 0;
}
*returnSize = digitsSize + 1;
return result;
}
3) Sqrt(x)
Given a non-negative integer x, return the square root of x rounded down to the nearest integer. The returned integer should be non-negative as well.
You must not use any built-in exponent function or operator.
For example, do not use pow(x, 0.5) in c++ or x ** 0.5 in python.
Example 1:
Input: x = 4
Output: 2
Explanation: The square root of 4 is 2, so we return 2.
Example 2:
Input: x = 8
Output: 2
Explanation: The square root of 8 is 2.82842..., and since we round it down to the nearest integer, 2 is returned.
Constraints:
0 <= x <= 231 - 1
Solution 1: O(n)
int mySqrt(int x) {
int right = 0;
for(int i = 1; i < x; i++) {
if ((i * i) > x) {
right = i;
break;
}
}
return (right - 1);
}
Solution 2: O(log n)
int mySqrt(int x) {
if((x == 0) || (x == 1)) return x;
long long left = 1;
long long right = x;
long long result = 0;
// binary search
while(left <= right) {
long long mid = left + (right - left) / 2;
long long square = mid * mid;
if (square == x) {
return (int)mid;
} else if (square < x) { // if mid*mid < square, move the window right.
left = mid + 1;
result = mid; // and remember the mid, in case next try will > x.
} else {
right = mid - 1;
}
}
return (int)result;
}
10. Sorting Alogrithm
1) Bubble Sort
void bubbleSort(int arr[], int n) {
for ( i = 0; i < n - 1; i++) {
for( j = 0; j < n - i -1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
2) Quick Sort
void quicksort(int *arr, int left, int right) {
if (left >= right) return;
int pivot = arr[(left + right) / 2];
int i = left - 1;
int j = right + 1;
while (1) {
while (arr[++i] < pivot);
while (arr[--j] > pivot);
if (i >= j) break;
// 交换 arr[i] 和 arr[j]
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
quicksort(arr, left, j);
quicksort(arr, j + 1, right);
}
11. Give the Output
1.
int main(void)
{
void (*p)(void);
int a = 0x100;
p=&a;
printf("a: %#x\n", a);
printf("p: %#x\n", p);
printf("*p: %#x\n", *p);
}
在这段代码中,我们首先要分析每一行的内容以及潜在的错误:
```c
#include <stdio.h>
int main(void)
{
void (*p)(void); // 声明一个函数指针,指向返回类型为 void 的函数
int a = 0x100; // 定义整型变量 a,赋值为 256(十六进制 0x100)
p = &a; // 将指针 p 赋值为 a 的地址,这里会引发警告或错误
printf("a: %#x\n", a);
printf("p: %#x\n", p);
printf("*p: %#x\n", *p); // 这里会导致未定义行为
}
```
### 代码分析
1. **函数指针声明**:`void (*p)(void);` 这行声明了一个指向返回类型为 `void` 的函数的指针 `p`,但尚未指向任何有效的函数。
2. **整数变量**:`int a = 0x100;` 初始化了 `a`,其值为十进制 256。
3. **指针赋值**:`p = &a;` 将指针 `p` 指向 `a` 的地址。这是一个错误,因为 `p` 是指向函数的指针,而 `a` 是一个整数。这样做会导致类型不匹配,通常会引发编译警告或错误。
4. **打印 `a` 的值**:`printf("a: %#x\n", a);` 将会打印 `a` 的值,输出将是:
```
a: 0x100
```
5. **打印 `p` 的值**:`printf("p: %#x\n", p);` 将打印指针 `p` 的值,即 `a` 的地址(假设为某个地址,例如 `0x7ffee3f56b0c`,具体地址依赖于编译器和运行环境)。
6. **解引用 `p`**:`printf("*p: %#x\n", *p);` 会尝试访问 `p` 所指向的值。由于 `p` 指向的是 `a` 的地址,而 `p` 本身是一个函数指针,解引用 `p` 将导致未定义行为。
### 可能的输出
由于存在未定义行为,实际输出可能会因编译器和运行环境的不同而有所不同。若假设无编译错误,输出可能类似于:
```
a: 0x100
p: 0x7ffee3f56b0c // 假设地址,实际地址会有所不同
* p: <未定义行为>
```
### 注意事项
由于代码中的指针类型不匹配,编译器可能会警告或错误,建议在编译时添加适当的类型检查和注释,以确保类型安全。
2. 类型提升
#include <stdio.h>
int main()
{
unsigned char a = 0xa5;
unsigned char b = ~a>>4 + 1;
printf("b=%d\n", b);
return 0;
}
### 分析代码时的关键点
```c
unsigned char a = 0xa5;
unsigned char b = ~a >> 4 + 1;
```
我们来逐步解析这个表达式。
### 详细步骤
1. **按位取反和类型提升**:
- `a = 0xA5`,其二进制表示为 `10100101`。
- `~a` 会将 `a` 取反,同时 `a` 从 `unsigned char` 提升到 `int` 类型。
- 因此,`~a` 计算得到 `0xFFFFFF5A`(假设 `int` 为 32 位),即 `11111111 11111111 11111111 01011010`。
2. **优先级计算**:
- 在表达式 `~a >> 4 + 1` 中,`4 + 1` 先计算,得到 `5`,因此整个表达式相当于 `~a >> 5`。
3. **右移操作**:
- 计算 `0xFFFFFF5A`(即 `11111111 11111111 11111111 01011010`)右移 5 位。
- 右移 5 位后,结果为:`11111111 11111111 11111111 11111010`。
4. **转换为无符号字符**:
- 右移结果是 `0xFFFFFFFA`(带符号的 -6)。
- 将 `0xFFFFFFFA` 赋值给 `unsigned char b` 时,会截断为低 8 位,即 `0xFA`,对应十进制为 `250`。
### 最终输出
因此,代码的输出为:
```plaintext
b=250
```

1284

被折叠的 条评论
为什么被折叠?



