Top100(上)
散列
struct MyListNode {
int val;
int pos;
struct MyListNode *next;
};
// 散列表
typedef struct {
struct MyListNode *data;
} MyHashMap;
const int hashSize = 1543;
MyHashMap *createHashMap() {
MyHashMap *hashMap = (MyHashMap *) malloc(sizeof(MyHashMap));
hashMap->data = (struct MyListNode *) malloc(sizeof(struct MyListNode) * hashSize);
for (int i = 0; i < hashSize; ++i) {
hashMap->data[i].val = 0x80000000;
hashMap->data[i].pos = -1;
hashMap->data[i].next = NULL;
}
return hashMap;
}
int hash(int key) {
return (key+1000000000) % hashSize;
}
struct MyListNode *getList(MyHashMap *hashMap, int key) {
return &(hashMap->data[hash(key)]);
}
int containsKey(MyHashMap *hashMap, int key) {
struct MyListNode *head = getList(hashMap, key);
while (head != NULL) {
if (head->val == key) return head->pos;
head = head->next;
}
return -1;
}
void insert(MyHashMap *hashMap, int key, int pos) {
if (containsKey(hashMap, key) != -1)return;
struct MyListNode *head = getList(hashMap, key);
struct MyListNode *node = (struct MyListNode *) malloc(sizeof(struct MyListNode));
node->val = key;
node->pos = pos;
node->next = head->next;
head->next = node;
}
int *twoSum(int *nums, int numsSize, int target, int *returnSize) {
int *res = (int *) malloc(sizeof(int) * 2);
*returnSize = 0;
MyHashMap *hashMap = (MyHashMap *) malloc(sizeof(MyHashMap));
hashMap = createHashMap();
for (int i = 0; i < numsSize; ++i) {
int t = containsKey(hashMap, target - nums[i]);
if (t != -1) {
res[0] = i;
res[1] = t;
*returnSize = 2;
return res;
} else {
insert(hashMap, nums[i], i);
}
}
return res;
}
// todo
// 字符串排序后放入hashmap
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
Map<String, List<String>> map = new HashMap<String, List<String>>();
for (String str : strs) {
// 字符串保存到字符数组
char[] chars = str.toCharArray();
// 对字符数组排序
Arrays.sort(chars);
String key = new String(chars);
List<String> list = map.getOrDefault(key, new ArrayList<String>());
// 把原始的字符串存入map中对应的list
list.add(str);
map.put(key, list);
}
return new ArrayList<List<String>>(map.values());
}
}
// 将每个出现次数大于0的字母和出现次数按顺序拼接成字符串,作为哈希表的键
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
Map<String, List<String>> map = new HashMap<String, List<String>>();
for (String str : strs) {
int[] counts = new int[26];
int length = str.length();
// 统计字符串中每个字母出现的次数
for (int i = 0; i < length; i++) {
counts[str.charAt(i) - 'a']++;
}
StringBuilder sb = new StringBuilder();
// 把出现的字符和出现的字数追加到key中
for (int i = 0; i < 26; i++) {
if (counts[i] != 0) {
sb.append((char) ('a' + i));
sb.append(counts[i]);
}
}
String key = sb.toString();
List<String> list = map.getOrDefault(key, new ArrayList<String>());
list.add(str);
map.put(key, list);
}
return new ArrayList<List<String>>(map.values());
}
}
struct Node {
char *value;
struct Node *next;
};
struct DummyNode {
// 记录排序后的字符串
char *sortedStr;
// 记录元素个数
int count;
struct Node *next;
};
typedef struct {
struct DummyNode *data;
// 当前有多少组已有元素
int groupCount;
int hashSize;
} HashMap;
int cmp(const void *a, const void *b) {
return *(char *) a - *(char *) b;
}
HashMap *createHashMap(int strsSize) {
HashMap *hashMap = (HashMap *) malloc(sizeof(HashMap));
// 组数最多也就是字符串的个数
hashMap->hashSize = strsSize;
hashMap->groupCount = 0;
// 为数组分配空间
hashMap->data = (struct DummyNode *) malloc(sizeof(struct DummyNode) * strsSize);
// 初始化hashMap,为每一组的虚拟头节点赋值
for (int i = 0; i < strsSize; ++i) {
hashMap->data[i].sortedStr = "";
hashMap->data[i].count = 0;
hashMap->data[i].next = NULL;
}
return hashMap;
}
// todo 可以优化查找
struct DummyNode *findNodeList(HashMap *hashMap, char *sorted) {
// 遍历所有非空组
for (int i = 0; i < hashMap->groupCount; ++i)
// 如果已经存在这一组,就返回该组的虚拟头节点
if (strcmp(hashMap->data[i].sortedStr, sorted) == 0)
return &(hashMap->data[i]);
// 不存在该组,则组数加一,返回当前组虚拟头节点
hashMap->data[hashMap->groupCount].sortedStr = (char *) malloc(sizeof(char) * (strlen(sorted) + 1));
strcpy(hashMap->data[hashMap->groupCount].sortedStr, sorted);
// *错误写法:hashMap->data[hashMap->groupCount].sortedStr = sorted;
hashMap->groupCount++;
return &(hashMap->data[hashMap->groupCount - 1]);
}
void addToHashMap(HashMap *hashMap, char *str) {
// 把字符串存入缓存,并把缓存中的字符排序
char buff[strlen(str) + 1];
strcpy(buff, str);
// strlen不要加一
qsort(buff, strlen(buff), sizeof(char), cmp);
// 头插法插入对应的组
struct DummyNode *dummyHead = findNodeList(hashMap, buff);
struct Node *node = (struct Node *) malloc(sizeof(struct Node));
node->value = str;
node->next = dummyHead->next;
dummyHead->next = node;
// 当前组元素个数加一
dummyHead->count++;
}
// 排序后分组
char ***groupAnagrams(char **strs, int strsSize, int *returnSize, int **returnColumnSizes) {
*returnSize = 0;
if (strsSize <= 0 || strs == NULL) return NULL;
HashMap *hashMap = createHashMap(strsSize);
// 记录到hashMap
for (int i = 0; i < strsSize; ++i)
addToHashMap(hashMap, strs[i]);
int groupCount = hashMap->groupCount;
*returnSize = groupCount;
char ***res = (char ***) malloc(sizeof(char **) * groupCount);
*returnColumnSizes = (int *) calloc(groupCount, sizeof(int));
for (int i = 0; i < groupCount; ++i) {
int len = hashMap->data[i].count;
// 记录当前组元素总数
(*returnColumnSizes)[i] = len;
res[i] = (char **) malloc(sizeof(char *) * len);
struct Node *cur = hashMap->data[i].next;
for (int j = 0; j < len; ++j) {
res[i][j] = cur->value;
cur = cur->next;
}
}
return res;
}
int cmp(const void *a, const void *b) {
return (*(int *) a) - (*(int *) b);
}
// 时间复杂度O(nlogn)
int longestConsecutive(int *nums, int numsSize) {
qsort(nums, numsSize, sizeof(int), cmp);
int maxLen = 0, tempLen = 0;
for (int i = 0; i < numsSize; ++i) {
if (i == 0) {
tempLen++;
maxLen = 1;
} else {
if (nums[i] - nums[i - 1] == 0) continue;
if (nums[i] - nums[i - 1] == 1) {
tempLen++;
if (tempLen > maxLen) maxLen = tempLen;
} else {
// 当前值不是前一个值加1,则这个值是一个新序列的开头
tempLen = 1;
}
}
}
return maxLen;
}
class Solution {
// 时间复杂度O(n)
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
// 加入集合,对数组去重
for (int num : nums) set.add(num);
int maxLen = 0;
for (Integer num : set) {
// 先检查上个元素是否出现在set中,如果有就不用重复统计tempLen了
if (!set.contains(num - 1)) {
// 如果上个元素不在set中,则这个元素就是这个序列的首个元素
int tempLen = 1;
int curNum = num + 1;
// 依次判断后续一个元素是否在set中
while (set.contains(curNum)) {
tempLen++;
curNum++;
}
maxLen = Math.max(tempLen, maxLen);
}
}
return maxLen;
}
}
双指针
void moveZeroes(int *nums, int numsSize) {
// slow指向当前应该存放非零元素的位置
int slow = 0;
// fast遇到非零元素时,就把元素移到nums[slow]中
int fast = 0;
while (fast < numsSize) {
if (nums[fast] != 0) {
nums[slow++] = nums[fast];
}
fast++;
}
// slow及其后面的都是0
while (slow < numsSize) {
nums[slow++] = 0;
}
}
int min(int a, int b) {
return a < b ? a : b;
}
int max(int a, int b) {
return a > b ? a : b;
}
// 暴力枚举
int maxArea(int *height, int heightSize) {
int res = 0;
for (int i = 0; i < heightSize; ++i) {
for (int j = i + 1; j < heightSize; ++j) {
int temp = (j - i) * min(height[i], height[j]);
res = max(res, temp);
}
}
return res;
}
int min(int a, int b) {
return a < b ? a : b;
}
int max(int a, int b) {
return a > b ? a : b;
}
int maxArea(int *height, int heightSize) {
int left = 0, right = heightSize - 1;
int res = 0;
while (left < right) {
int temp = (right - left) * min(height[left], height[right]);
res = max(res, temp);
// 每次把短板往里移动,短板可能变长,总面积才可能变大
// 如果移动长板,底一定变小,高度不会超过之前的那个短板,高只会原来越低,面积只会变小
if (height[left] < height[right])
left++;
else
right--;
}
return res;
}
int cmp(const void *a, const void *b) {
return (*(int *) a) - (*(int *) b);
}
// 三元组最大个数
const int SIZE = 20000;
int **threeSum(int *nums, int numsSize, int *returnSize, int **returnColumnSizes) {
if (nums == NULL || numsSize < 3) return NULL;
int **res = (int **) malloc(sizeof(int *) * SIZE);
int index = 0;
*returnColumnSizes = (int *) malloc(sizeof(int) * SIZE);
*returnSize = 0;
// 排序
qsort(nums, numsSize, sizeof(int), cmp);
// 排序后最后一个数小于0时,不符合题意
if (nums[numsSize - 1] < 0) return NULL;
for (int i = 0; i < numsSize - 2; ++i) {
// 当前值都大于0了,后面就没必要找了
if (nums[i] > 0) break;
if (i > 0) {
// 上一个固定i的情况已经讨论完了,包括nums[left],nums[right]也等于nums[i]的情况
// i必须更新到下一个值不同的地方
while ((i < numsSize - 2) && nums[i] == nums[i - 1]) i++;
}
int left = i + 1, right = numsSize - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
res[index] = (int *) malloc(sizeof(int) * 3);
res[index][0] = nums[i];
res[index][1] = nums[left];
res[index][2] = nums[right];
index++;
// 当前的left,right,i是符合要求的三元组
// 固定i,同时变动left,right使nums[left],nums[right]都变成新的值
// 若只变动left,right中的一个,那这三个数一定不符合题意,因为原来的三个刚好符合题意
// 把left移到与当前值相同的最后一个位置
while (left < right && nums[left] == nums[left + 1]) left++;
// 把left移动到和当前值不同的第一个位置
left++;
while (left < right && nums[right] == nums[right - 1]) right--;
right--;
// left,right找完了,跳出循环,修改i
if (left >= right) break;
} else if (sum > 0) {
// right移到比当前值小的下一个元素
while (left < right && nums[right] == nums[right - 1]) right--;
right--;
} else {
// left移到比当前值大的下一个元素
while (left < right && nums[left] == nums[left + 1]) left++;
left++;
}
}
}
*returnSize = index;
*returnColumnSizes = (int *) malloc(sizeof(int) * index);
for (int i = 0; i < index; ++i) {
(*returnColumnSizes)[i] = 3;
}
return res;
}
// 按行累积,每次累加当前行上能接多少水(超时)
int trap(int *height, int heightSize) {
int res = 0;
int lever = 1;
// 找最大高度
int maxHeight = 0;
for (int i = 0; i < heightSize; ++i)
if (height[i] > maxHeight) maxHeight = height[i];
// 每次找一层,一格一格的加
while (lever <= maxHeight) {
int i = 0;
// 找到第一个不低于当前lever的作为左边界
while (i < heightSize && height[i] < lever) i++;
if (i >= heightSize) continue;
int temp = 0;
while (i < heightSize) {
if (height[i] < lever) {
// 已有左边界,并且比当前层低,说明这个格子(i, lever)可以放水
temp++;
} else if (height[i] >= lever) {
// 找到大于或等于当前层的右边界,就把之前累积的水加到结果中,并清空temp
// 当前的右边界变成下一个左边界,在继续寻找下一个右边界
res += temp;
temp = 0;
}
i++;
}
lever++;
}
return res;
}
int findMax(int *height, int start, int end) {
int max = height[start];
while (start <= end) {
if (height[start] > max) max = height[start];
start++;
}
return max;
}
// 按列累积,每次累加当前列上能接多少水
int trap(int *height, int heightSize) {
int res = 0;
// 记录当前元素左边的最大值
int tempLeftMax = height[0];
int leftMaxArr[heightSize];
for (int i = 1; i <= heightSize - 2; ++i) {
leftMaxArr[i] = tempLeftMax;
if (height[i] > tempLeftMax) tempLeftMax = height[i];
}
// 记录当前元素右边的最大值
int tempRightMax = height[heightSize - 1];
int rightMaxArr[heightSize];
for (int i = heightSize - 2; i >= 1; i--) {
rightMaxArr[i] = tempRightMax;
if (height[i] > tempRightMax) tempRightMax = height[i];
}
for (int i = 1; i < heightSize - 1; ++i) {
// 找左右两边最高的列
// 1.大量重复寻找会超时
// int leftMax = findMax(height, 0, i - 1);
// int rightMax = findMax(height, i + 1, heightSize - 1);
// 2.两边遍历保存结果
int leftMax = leftMaxArr[i];
int rightMax = rightMaxArr[i];
int min = leftMax < rightMax ? leftMax : rightMax;
// 只有左边最高的和右边最高的,二者中的较小者比当年的列高,当前列才能接得住水
// 较小者小于等于当前列,接不住水
if (min > height[i]) res += min - height[i];
}
return res;
}
// 用leftMax优化掉leftMaxArr数组
// 由于i是从左往右,所以rightMaxArr没法用这个办法优化掉
int trap(int *height, int heightSize) {
int res = 0;
// 记录当前元素右边的最大值
int tempRightMax = height[heightSize - 1];
int rightMaxArr[heightSize];
for (int i = heightSize - 2; i >= 1; i--) {
rightMaxArr[i] = tempRightMax;
if (height[i] > tempRightMax) tempRightMax = height[i];
}
// *记录当前元素左边的最大值
int leftMax = height[0], rightMax;
for (int i = 1; i < heightSize - 1; ++i) {
// 找左右两边最高的列
rightMax = rightMaxArr[i];
int min = leftMax < rightMax ? leftMax : rightMax;
// 只有左边最高的和右边最高的,二者中的较小者比当年的列高,当前列才能接得住水
// 较小者小于等于当前列,接不住水
if (min > height[i]) res += min - height[i];
// *更新leftMax
if (height[i] > leftMax) leftMax = height[i];
}
return res;
}
// 双指针优化掉leftMaxArr、rightMaxArr
int trap(int *height, int heightSize) {
int res = 0;
// 柱子能接到的水 = min{左右两边最高的柱子} - 当前柱子的高度
// L、R是两根柱子,本应该有L的两个变量leftMaxOfL、rightMaxOfL和R的两个变量leftMaxOfR、rightMaxOfR
// 由于L < R,所以leftMaxOfL <= leftMaxOfR,rightMaxOfR <= rightMaxOfL
// 从而如果leftMaxOfL > rightMaxOfR,则一定有leftMaxOfR >= rightMaxOfR,即在R处,左边最高的柱子大于右边最高的柱子,此时可以计算在R处能接到的水
// 如果leftMaxOfL < rightMaxOfR,则一定有rightMaxOfL >= leftMaxOfL,即在L处,右边最高的柱子大于左边最高的柱子,此时可以计算在L处能接到的水
// 实际上只用到了leftMaxOfL和rightMaxOfR这两个变量
// 记录当前元素左边的最大值
int leftMaxOfL = height[0], rightMaxOfR = height[heightSize - 1];
// 双指针,L、R代替原来的i
int L = 1, R = heightSize - 2;
for (int i = 1; i < heightSize - 1; ++i) {
// leftMaxOfL = leftMaxArr[L] = max(leftMaxArr[L-1], height[L-1])
// 即当前位置的左侧最大元素,是上个元素的左侧最大元素和上个元素两者中的较大者,height[L-1]是可能成为leftMax的变量
// 同理,当前位置的右侧最大元素,是后个元素的右侧最大元素和后个元素两者中的较大者,height[R+1]是可能成为rightMax的变量
if (height[L - 1] < height[R + 1]) {
// 从左往右更新
// 当height[L-1] < height[R+1]时,一定有leftMaxOfL < rightMaxOfR todo ???
// [1,5,3,4,2,6]
// 此时min=leftMaxOfL
int min = leftMaxOfL;
if (min > height[L]) res += min - height[L];
// 更新leftMax
if (height[L] > leftMaxOfL) leftMaxOfL = height[L];
L++;
} else {
// 从右往左更新
int min = rightMaxOfR;
if (min > height[R]) res += min - height[R];
// 更新rightMax
if (height[R] > rightMaxOfR) rightMaxOfR = height[R];
R--;
}
}
return res;
}
// todo 栈
int trap(int *height, int heightSize) {
int res = 0;
int stack[heightSize];
int top = 0;
int current = 0;
while (current < heightSize) {
// 当前高度大于栈顶高度,说明之前的地方能接水,持续出栈到栈顶高度大于等于当前高度或者直到栈空为止
while (top > 0 && height[current] > height[stack[top - 1]]) {
// 栈顶出栈
int h = height[stack[top - 1]];
top--;
if (top == 0) break;
// 两个柱子间的距离
int distance = current - stack[top - 1] - 1;
// 新的栈顶高度和当前高度的较小者
int min = height[stack[top - 1]] < height[current] ? height[stack[top - 1]] : height[current];
res += distance * (min - h);
}
stack[top++] = current;
current++;
}
return res;
}
滑动窗口
int lengthOfLongestSubstring(char *s) {
int len = strlen(s);
if (len < 2) return len;
// 记录当前在滑动窗口中的字符
int *hashSet = (int *) calloc(128, sizeof(int));
int left = 0, right = 0;
hashSet[s[right]] = 1;
int res = 1;
while (right + 1 < len) {
// 待进入窗口的下个字符
char nextChar = s[right + 1];
if (hashSet[nextChar] == 0) {
// 未出现过就加入到窗口中
hashSet[nextChar] = 1;
right++;
// 更新最大长度
if ((right - left + 1) > res) res = right - left + 1;
} else {
// 已经出现在窗口中,就移动left
while (left <= right && s[left] != nextChar) {
// 去掉left之前的字符
hashSet[s[left]] = 0;
left++;
}
// 此时s[left]和nextChar相等
// 窗口整体右移一格
left++;
right++;
}
}
return res;
}
int *findAnagrams(char *s, char *p, int *returnSize) {
*returnSize = 0;
int lenS = strlen(s);
int lenP = strlen(p);
if (lenS < lenP) return NULL;
int *res = (int *) malloc(sizeof(int) * (lenS - lenP + 1));
int *count = (int *) calloc(26, sizeof(int));
// 记录count数组中不为0的个数
int differ = 0;
for (int i = 0; i < lenP; ++i) {
// 累加p中对应字符出现的次数
count[p[i] - 'a']++;
// 减去s中已经出现的字符的次数
count[s[i] - 'a']--;
}
// 记录不为0的个数
for (int i = 0; i < 26; ++i)
if (count[i] != 0) differ++;
// 若刚好抵消掉p中各个字符出现的次数,说明是异位词
if (differ == 0) res[(*returnSize)++] = 0;
// 窗口左右两端
int left = 1, right = lenP;
// 开始滑动窗口,窗口大小和p的长度一致
while (right < lenS) {
// left-1移除窗口
// 移动之前就是0,说明移动后不为0的字符会多一个
if (count[s[left - 1] - 'a'] == 0) differ++;
count[s[left - 1] - 'a']++;
// 移动之后是0,说明移动后不为0的字符会少一个
if (count[s[left - 1] - 'a'] == 0) differ--;
// right移入窗口
if (count[s[right] - 'a'] == 0) differ++;
count[s[right] - 'a']--;
if (count[s[right] - 'a'] == 0) differ--;
if (differ == 0) res[(*returnSize)++] = left;
left++;
right++;
}
return res;
}
子串
// 暴力枚举(超时)
int subarraySum(int *nums, int numsSize, int k) {
int res = 0;
for (int i = 0; i < numsSize; ++i) {
int tempSum = 0;
for (int j = i; j < numsSize; ++j) {
tempSum += nums[j];
if (tempSum == k) res++;
}
}
return res;
}
// 记录前缀和(超时)
int subarraySum(int *nums, int numsSize, int k) {
int *prefixSum = (int *) calloc(numsSize + 1, sizeof(int));
for (int i = 1; i <= numsSize; ++i) {
prefixSum[i] = prefixSum[i - 1] + nums[i - 1];
}
int res = 0;
for (int i = 0; i < numsSize; ++i) {
for (int j = i; j < numsSize; ++j) {
if (prefixSum[j + 1] - prefixSum[i] == k) res++;
}
}
return res;
}
// todo
// 只关心有多少个prefixSum[j]满足prefixSum[j]等于prefixSum[i] - k,不关心j的具体位置
int subarraySum(int *nums, int numsSize, int k) {
int res = 0;
const int size = 20000 * 1000;
// 最多20000个数,和的范围是[-20000000, 20000000],右移20000000,使其下标从0开始,[0, 40000000]
int *hashMap = (int *) calloc(size * 2, sizeof(int));
// 记录前缀和(prefixSum[i]不包括i处的元素)
// j < i, prefixSum[i] - prefixSum[j] = k时,说明[j, i-1]就是一个和为k的子数组
// 转化为累加prefixSum[j]等于prefixSum[i] - k的个数
int *prefixSum = (int *) calloc(numsSize + 1, sizeof(int));
// 第一个元素的前缀和是0,单独记录下这个0出现过一次(不然就修改定义,prefixSum[i]改成包括i处的元素)
hashMap[0 + size]++;
for (int i = 1; i <= numsSize; ++i) {
prefixSum[i] = prefixSum[i - 1] + nums[i - 1];
res += hashMap[prefixSum[i] - k + size];
// 累加前缀和为prefixSum[i]出现的次数
hashMap[prefixSum[i] + size]++;
}
return res;
}
普通数组
int maxSubArray(int *nums, int numsSize) {
int res = nums[0];
// dp[i]表示到i位置的最大连续子数组之和的最大值(错,有后效性,因为不确定i在子数组中是第几个元素)
// dp[i]表示以i位置结尾的最大连续子数组之和的最大值(对,无后效性)
int dp[numsSize];
dp[0] = nums[0];
for (int i = 1; i < numsSize; ++i) {
// 必须以nums[i]结尾
if (dp[i - 1] > 0)
dp[i] = dp[i - 1] + nums[i];
else
dp[i] = nums[i];
if (dp[i] > res) res = dp[i];
}
return res;
}
// dp[i]只和dp[i-1]相关,可以使用滚动变量优化
int maxSubArray(int *nums, int numsSize) {
int res = nums[0];
// pre表示以i位置结尾的最大连续子数组之和的最大值
int pre = nums[0];
for (int i = 1; i < numsSize; ++i) {
// 必须以nums[i]结尾
if (pre > 0)
pre = pre + nums[i];
else
pre = nums[i];
if (pre > res) res = pre;
}
return res;
}
int max(int a, int b, int c) {
int d = a > b ? a : b;
return d > c ? d : c;
}
// 必须经过mid和mid+1
int maxCrossingSum(int *nums, int left, int mid, int right) {
int leftMax = nums[mid];
int rightMax = nums[mid + 1];
int index = mid;
int tempMax = 0;
// 找左边以mid结尾的最大连续子数组的和
while (index >= left) {
tempMax += nums[index];
if (tempMax > leftMax) leftMax = tempMax;
index--;
}
index = mid + 1;
tempMax = 0;
// 找右边以mid+1开头的最大连续子数组的和
while (index <= right) {
tempMax += nums[index];
if (tempMax > rightMax) rightMax = tempMax;
index++;
}
return leftMax + rightMax;
}
int maxSubArraySum(int *nums, int left, int right) {
if (left == right) return nums[left];
// 中偏左
int mid = left + ((right - left) >> 1);
// 分三类,包含所有情况
// 第一类:以mid结尾的
// 第二类:以mid+1开头的
// 第三类:经过mid和mid+1的
return max(maxSubArraySum(nums, left, mid),
maxSubArraySum(nums, mid + 1, right),
maxCrossingSum(nums, left, mid, right));
}
// 分治
int maxSubArray(int *nums, int numsSize) {
if (numsSize == 0) return 0;
return maxSubArraySum(nums, 0, numsSize - 1);
}
int cmp(const int **a, const int **b) {
return *a[0] > *b[0];
}
int **merge(int **intervals, int intervalsSize, int *intervalsColSize, int *returnSize, int **returnColumnSizes) {
*returnSize = 0;
int **res = (int **) malloc(sizeof(int *) * intervalsSize);
*returnColumnSizes = (int *) malloc(sizeof(int) * intervalsSize);
for (int i = 0; i < intervalsSize; ++i) {
res[i] = (int *) malloc(sizeof(int) * 2);
(*returnColumnSizes)[i] = 2;
}
// 按第一列排序
qsort(intervals, intervalsSize, sizeof(int) * 2, cmp);
for (int i = 0; i < intervalsSize; ++i) {
int left = intervals[i][0];
int right = intervals[i][1];
// 合并
while ((i < intervalsSize - 1) && right >= intervals[i + 1][0]) {
if (intervals[i + 1][1] > right) right = intervals[i + 1][1];
i++;
}
res[*returnSize][0] = left;
res[*returnSize][1] = right;
(*returnSize)++;
}
return res;
}
void reverse(int *nums, int left, int right) {
int temp;
while (left < right) {
temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
left++;
right--;
}
}
// 三次原地反转
void rotate(int *nums, int numsSize, int k) {
k %= numsSize;
reverse(nums, 0, numsSize - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, numsSize - 1);
}
int *productExceptSelf(int *nums, int numsSize, int *returnSize) {
*returnSize = numsSize;
int *res = (int *) malloc(sizeof(int) * numsSize);
// 记录左右乘积
int leftMulArray[numsSize], rightMulArray[numsSize];
leftMulArray[0] = 1;
for (int i = 1; i < numsSize; ++i)
leftMulArray[i] = leftMulArray[i - 1] * nums[i - 1];
rightMulArray[numsSize - 1] = 1;
for (int i = numsSize - 2; i >= 0; i--)
rightMulArray[i] = rightMulArray[i + 1] * nums[i + 1];
// 左右乘积相乘
for (int i = 0; i < numsSize; ++i)
res[i] = leftMulArray[i] * rightMulArray[i];
return res;
}
// 空间复杂度O(1)
int *productExceptSelf(int *nums, int numsSize, int *returnSize) {
*returnSize = numsSize;
int *res = (int *) malloc(sizeof(int) * numsSize);
res[0] = 1;
// 左边乘积存入res
for (int i = 1; i < numsSize; ++i)
res[i] = res[i - 1] * nums[i - 1];
// 右边乘积存入rightMul
int rightMul = 1;
for (int i = numsSize - 2; i >= 0; i--) {
rightMul = rightMul * nums[i + 1];
// 左右乘积相乘
res[i] = res[i] * rightMul;
}
return res;
}
class Solution {
public:
// 原地映射:把值为 value 的元素映射到数组中下标为 value-1 的位置
int firstMissingPositive(vector<int> &nums) {
int length = nums.size();
// 待映射的值
int value;
// 临时保存被 value 重新映射后覆盖掉的值,之后再判断 temp 是否也需要重新映射
int temp;
for (int i = 0; i < length; ++i) {
// 跳过映射不到数组中的元素
if (nums[i] <= 0 || nums[i] > length) continue;
// 跳过已经映射好的元素
if (nums[i] == i + 1) continue;
// 准备重新映射nums[i]
value = nums[i];
// 把原来的位置设置-1,表示这个位置已经处理过了
nums[i] = -1;
// 保存可能需要映射的 nums[value - 1]
temp = nums[value - 1];
// 把值为 value 的元素映射到数组中下标为 value-1 的位置
nums[value - 1] = value;
// 如果 temp 也能映射到数组中,并且尚未映射过
while (temp > 0 && temp <= length && nums[temp - 1] != temp) {
value = temp;
temp = nums[value - 1];
nums[value - 1] = value;
}
}
// 遍历寻找第一个空缺
for (int j = 0; j < length; ++j)
if (nums[j] != j + 1)
return j + 1;
// 重新映射后,数组中没有空缺(没有值-1),说明缺失的第一个正数就是 length + 1
return length + 1;
}
};
class Solution {
public:
// 原地映射:把值为 value 的元素映射到数组中下标为 value-1 的位置
// 优化了对映射后覆盖掉的值的处理
int firstMissingPositive(vector<int> &nums) {
int length = nums.size();
for (int i = 0; i < length; ++i) {
// 如果 nums[i] 也能映射到数组中,并且尚未映射过
while (nums[i] > 0 && nums[i] <= length && nums[nums[i] - 1] != nums[i]) {
// 把 nums[i] 映射到 nums[nums[i] - 1],nums[nums[i] - 1] 放在 nums[i]
// 然后继续判断新的 nums[i] 是否也需要映射
swap(nums[nums[i] - 1], nums[i]);
}
}
// 遍历寻找第一个空缺
for (int i = 0; i < length; ++i)
if (nums[i] != i + 1)
return i + 1;
// 重新映射后,数组中没有空缺(没有值-1),说明缺失的第一个正数就是 length + 1
return length + 1;
}
};
class Solution {
public:
// 原地映射:把可以映射到的地方的元素改成负数
int firstMissingPositive(vector<int> &nums) {
int length = nums.size();
// 非正数改成 length + 1
for (int &value: nums)
if (value <= 0) value = length + 1;
for (int i = 0; i < length; ++i) {
// 待映射的值
int value = abs(nums[i]);
// 如果可以映射到数组里,就把映射到的地方的元素改成负数
// 用负数标记已经被映射过,而不是通过 nums[value-1] == value 来判断
if (value <= length) nums[value - 1] = -abs(nums[value - 1]);
}
for (int i = 0; i < length; ++i)
if (nums[i] > 0) return i + 1;
// 重新映射后,数组中没有空缺(没有值大于0),说明缺失的第一个正数就是 length + 1
return length + 1;
}
};
矩阵
void setZeroes(int **matrix, int matrixSize, int *matrixColSize) {
int *hashMapRow = (int *) calloc(matrixSize, sizeof(int));
int *hashMapColumn = (int *) calloc(*matrixColSize, sizeof(int));
for (int i = 0; i < matrixSize; ++i) {
for (int j = 0; j < *matrixColSize; ++j) {
if (matrix[i][j] == 0) {
// 记录下i行j列,等会置零
hashMapRow[i] = 1;
hashMapColumn[j] = 1;
}
}
}
for (int i = 0; i < matrixSize; ++i)
for (int j = 0; j < *matrixColSize; ++j)
if (hashMapRow[i] == 1 || hashMapColumn[j] == 1) matrix[i][j] = 0;
}
// 空间复杂度O(1)
void setZeroes(int **matrix, int matrixSize, int *matrixColSize) {
bool flagRow = false;
bool flagColumn = false;
// 判断首行首列是否要同时置零
bool flag = matrix[0][0] == 0;
for (int i = 0; i < matrixSize; ++i) {
for (int j = 0; j < *matrixColSize; ++j) {
if (matrix[i][j] == 0) {
if (i == 0) {
// 第一行要置零
flagRow = true;
continue;
}
if (j == 0) {
// 第一列要置零
flagColumn = true;
continue;
}
// 用原矩阵的第一行第一列标记是否要置零
matrix[0][j] = 0;
matrix[i][0] = 0;
}
}
}
// 先处理除了第一行第一列其他的位置
for (int i = 1; i < matrixSize; ++i)
for (int j = 1; j < *matrixColSize; ++j)
if (matrix[0][j] == 0 || matrix[i][0] == 0) matrix[i][j] = 0;
// 处理第一行第一列
if (flag || flagRow)
for (int i = 0; i < *matrixColSize; ++i) matrix[0][i] = 0;
if (flag || flagColumn)
for (int i = 0; i < matrixSize; ++i) matrix[i][0] = 0;
}
int *spiralOrder(int **matrix, int matrixSize, int *matrixColSize, int *returnSize) {
*returnSize = matrixSize * (*matrixColSize);
int *res = (int *) malloc(sizeof(int) * (*returnSize));
int index = 0;
// 上下边界
int up = 0, down = matrixSize - 1;
// 左右边界
int left = 0, right = *matrixColSize - 1;
while (true) {
// 向右处理up行
for (int i = left; i <= right; ++i)
res[index++] = matrix[up][i];
if (++up > down) break;
// 向下处理right列
for (int i = up; i <= down; ++i)
res[index++] = matrix[i][right];
if (--right < left)break;
// 向左处理down行
for (int i = right; i >= left; i--)
res[index++] = matrix[down][i];
if (--down < up)break;
// 向上处理left列
for (int i = down; i >= up; i--)
res[index++] = matrix[i][left];
if (++left > right) break;
}
return res;
}
void rotate(int **matrix, int matrixSize, int *matrixColSize) {
int temp[matrixSize][matrixSize];
// 放到新矩阵中
for (int i = 0; i < matrixSize; ++i) {
for (int j = 0; j < matrixSize; ++j) {
temp[j][matrixSize - 1 - i] = matrix[i][j];
}
}
// 放回原矩阵
for (int i = 0; i < matrixSize; ++i)
for (int j = 0; j < matrixSize; ++j)
matrix[i][j] = temp[i][j];
}
// todo 原地旋转
void rotate(int **matrix, int matrixSize, int *matrixColSize) {
for (int i = 0; i < matrixSize / 2; ++i) {
for (int j = 0; j < (matrixSize + 1) / 2; ++j) {
int temp = matrix[i][j];
matrix[i][j] = matrix[matrixSize - j - 1][i];
matrix[matrixSize - j - 1][i] = matrix[matrixSize - i - 1][matrixSize - j - 1];
matrix[matrixSize - i - 1][matrixSize - j - 1] = matrix[j][matrixSize - i - 1];
matrix[j][matrixSize - i - 1] = temp;
}
}
}
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
void rotate(int **matrix, int matrixSize, int *matrixColSize) {
// 水平翻转
for (int i = 0; i < matrixSize / 2; ++i)
for (int j = 0; j < matrixSize; ++j)
swap(&matrix[i][j], &matrix[matrixSize - 1 - i][j]);
// 主对角线翻转
for (int i = 0; i < matrixSize; ++i)
for (int j = i + 1; j < matrixSize; ++j)
swap(&matrix[i][j], &matrix[j][i]);
}
bool binarySearch(int *array, int left, int right, int target) {
int mid;
while (left <= right) {
mid = left + ((right - left) >> 1);
if (array[mid] == target) {
return true;
} else if (array[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return false;
}
// 一行一行的二分查找
bool searchMatrix(int **matrix, int matrixSize, int *matrixColSize, int target) {
for (int i = 0; i < matrixSize; ++i)
if (binarySearch(matrix[i], 0, *matrixColSize - 1, target)) return true;
return false;
}
// 从右上角往左或者往下遍历
bool searchMatrix(int **matrix, int matrixSize, int *matrixColSize, int target) {
int row = 0, column = *matrixColSize - 1;
while (row < matrixSize && column >= 0) {
int cur = matrix[row][column];
if (cur == target)
return true;
else if (cur > target)
// 往左
column--;
else
// 往下
row++;
}
return false;
}
// todo 有bug
void display(int **matrix, int matrixSize, int *matrixColSize) {
for (int i = 0; i < matrixSize; ++i) {
for (int j = 0; j < *matrixColSize; ++j) {
printf("%d ", matrix[i][j]);
}
puts("");
}
puts("");
}
bool search(int **matrix, int left, int right, int up, int down, int target) {
if (left > right || up > down) return false;
if (left == right && up == down) return matrix[left][up] == target;
if (left == right - 1 && up == down - 1) {
return matrix[left][up] == target
|| matrix[left + 1][up] == target
|| matrix[left][up + 1] == target
|| matrix[left + 1][up + 1] == target;
}
int midRow = up + ((down - up) >> 1);
int midColumn = left + ((right - left) >> 1);
int cur = matrix[midRow][midColumn];
printf("left=%d right=%d up=%d down=%d midRow=%d midColumn=%d cur=%d\n", left, right, up, down, midRow, midColumn,
cur);
if (cur == target) return true;
if (cur > target) {
// 丢弃右下角(右下角全都大于target)
puts("左上角");
bool a = search(matrix, left, midColumn, up, midRow, target); // 左上角
puts("右上角");
bool b = search(matrix, midColumn + 1, right, up, midRow - 1, target); // 右上角
puts("左下角");
bool c = search(matrix, left, midColumn - 1, midRow + 1, down, target); // 左下角
return a || b || c;
// return search(matrix, left, midColumn, up, midRow, target) // 左上角
// || search(matrix, midColumn + 1, right, up, midRow - 1, target) // 右上角
// || search(matrix, left, midColumn - 1, midRow + 1, down, target); // 左下角
} else {
// 丢弃左上角(左上角全都小于target)
puts("右下角");
bool a = search(matrix, midColumn, right, midRow, down, target); // 右下角
puts("右上角");
bool b = search(matrix, midColumn + 1, right, up, midRow - 1, target); // 右上角
puts("左下角");
bool c = search(matrix, left, midColumn - 1, midRow + 1, down, target); // 左下角
return a || b || c;
// return search(matrix, midColumn, right, midRow, down, target) // 右下角
// || search(matrix, midColumn + 1, right, up, midRow - 1, target) // 右上角
// || search(matrix, left, midColumn - 1, midRow + 1, down, target); // 左下角
}
}
bool searchMatrix(int **matrix, int matrixSize, int *matrixColSize, int target) {
display(matrix, matrixSize, matrixColSize);
return search(matrix, 0, *matrixColSize - 1, 0, matrixSize - 1, target);
}
链表
// 返回两个单链表相交的起始节点
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
int len1 = 0, len2 = 0;
struct ListNode *p = headA, *q = headB;
// 求长度
while (p != NULL) {
len1++;
p = p->next;
}
while (q != NULL) {
len2++;
q = q->next;
}
// 长链表先走
p = headA;
q = headB;
if (len1 > len2)
for (int i = 0; i < len1 - len2; ++i)
p = p->next;
else
for (int i = 0; i < len2 - len1; ++i)
q = q->next;
// p、q距离尾节点距离相同时,同时出发
while (p != NULL) {
if (p == q)return p;
p = p->next;
q = q->next;
}
return NULL;
}
// 迭代
struct ListNode *reverseList(struct ListNode *head) {
struct ListNode *pre = NULL;
struct ListNode *next;
struct ListNode *cur = head;
// 原地反转
while (cur != NULL) {
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
// 递归
struct ListNode *reverseList(struct ListNode *head) {
// 递归出口
if (head == NULL || head->next == NULL) return head;
// 递归式
struct ListNode *newHead = reverseList(head->next); // 递归反转后面的链表
head->next->next = head; // 下个结点也就是反转后的尾节点,指向自己
head->next = NULL; // 自己作为新的尾节点
return newHead;
}
// 返回向上取整的中间节点
struct ListNode *findMid(struct ListNode *head) {
struct ListNode *slow = head;
struct ListNode *fast = head;
while (fast != NULL && fast->next != NULL) {
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
// 原地反转
struct ListNode *reverseList(struct ListNode *head) {
struct ListNode *pre = NULL;
struct ListNode *cur = head;
struct ListNode *next;
while (cur != NULL) {
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
bool isPalindrome(struct ListNode *head) {
struct ListNode *mid = findMid(head);
mid = reverseList(mid);
struct ListNode *p = head;
struct ListNode *q = mid;
while (q != NULL) {
if (p->val != q->val) return false;
p = p->next;
q = q->next;
}
return true;
}
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
if (head == NULL || head->next == NULL) return false;
struct ListNode *slow = head;
struct ListNode *fast = head->next;
while (fast != NULL && fast->next != NULL) {
if (slow == fast)return true;
slow = slow->next;
fast = fast->next->next;
}
return false;
}
// todo
struct ListNode *detectCycle(struct ListNode *head) {
// 环外节点数a 环内节点数b
// 快慢指针经过的节点个数关系: f = 2s
// 相遇时: f = s + n*b -> s = n*b, f = 2*n*b
// 走到入口节点经过的节点个数k = a + n*b, 先前进a步到入口节点, 然后在环里转圈
// f = 0, s = n*b -> f = a, s = a + n*b相遇在入口节点
struct ListNode *slow = head, *fast = head;
while (fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
// 首次相遇时,slow已经跑了b步,只需跑a步就能到达入口
// fast返回开头head节点,也只需跑a步就能到达入口
// 此时a是几并不知道,但是可以确定的是,slow和fast都在跑a步就会在入口相遇
if (slow == fast) {
fast = head;
// 此时f = 0, s = 1*b
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
// 结束时f = a, s = a + 1*b
return slow;
}
}
return NULL;
}
// 递归
struct ListNode *mergeTwoLists(struct ListNode *list1, struct ListNode *list2) {
// 递归出口
if (list1 == NULL) return list2;
if (list2 == NULL) return list1;
// 递归体
if (list1->val < list2->val) {
list1->next = mergeTwoLists(list1->next, list2);
return list1;
} else {
list2->next = mergeTwoLists(list1, list2->next);
return list2;
}
}
// 先反转两个链表,再从低位往高位计算,记录进位
struct ListNode *addTwoNumbers(struct ListNode *l1, struct ListNode *l2) {
struct ListNode *n1 = (l1);
struct ListNode *n2 = (l2);
struct ListNode *dummyHead = (struct ListNode *) malloc(sizeof(struct ListNode));
dummyHead->next = NULL;
struct ListNode *pre = dummyHead;
// 进位
int carry = 0;
while (n1 != NULL && n2 != NULL) {
struct ListNode *node = (struct ListNode *) malloc(sizeof(struct ListNode));
node->next = NULL;
// 计算
node->val = (n1->val + n2->val + carry) % 10;
carry = (n1->val + n2->val + carry) / 10;
// 拼接
pre->next = node;
pre = pre->next;
n1 = n1->next;
n2 = n2->next;
}
while (n1 != NULL) {
struct ListNode *node = (struct ListNode *) malloc(sizeof(struct ListNode));
node->next = NULL;
node->val = (n1->val + carry) % 10;
carry = (n1->val + carry) / 10;
pre->next = node;
pre = pre->next;
n1 = n1->next;
}
while (n2 != NULL) {
struct ListNode *node = (struct ListNode *) malloc(sizeof(struct ListNode));
node->next = NULL;
node->val = (n2->val + carry) % 10;
carry = (n2->val + carry) / 10;
pre->next = node;
pre = pre->next;
n2 = n2->next;
}
// 进位可能导致最后多出一位
if (carry == 1) {
struct ListNode *node = (struct ListNode *) malloc(sizeof(struct ListNode));
node->next = NULL;
node->val = 1;
pre->next = node;
}
return (dummyHead->next);
}
struct ListNode *removeNthFromEnd(struct ListNode *head, int n) {
struct ListNode *dummyHead = (struct ListNode *) malloc(sizeof(struct ListNode));
dummyHead->next = head;
struct ListNode *slow = dummyHead, *fast = dummyHead;
int count = n + 1;
while (count-- > 0) fast = fast->next;
while (fast != NULL) {
slow = slow->next;
fast = fast->next;
}
slow->next = slow->next->next;
return dummyHead->next;
}
struct ListNode *swapPairs(struct ListNode *head) {
if (head == NULL || head->next == NULL) return head;
struct ListNode *nextNode = head->next->next;
struct ListNode *right = head->next;
right->next = head;
head->next = swapPairs(nextNode);
return right;
}
class Solution {
public:
ListNode *reverseList(ListNode *head, ListNode *tail) {
ListNode *pre = tail->next, *cur = head, *next;
ListNode *nextNode = tail->next;
while (cur != nullptr && cur != nextNode) {
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
ListNode *reverseKGroup(ListNode *head, int k) {
// 虚拟头节点,接在链表最前面,使得第一段要反转的链表部分的处理和后面统一
ListNode *dummyHead = new ListNode(0, head);
ListNode *pre = dummyHead;
ListNode *left = dummyHead;
ListNode *right;
// 后移次数
int count;
while (pre->next != nullptr) {
// left、right 移到下一段要反转的链表的头部
left = pre->next;
right = left;
// right 后移 k-1 个节点
for (count = k - 1; count != 0 && right->next != nullptr; count--) {
right = right->next;
}
// 链表元素总数小于 k
if (count != 0) return dummyHead->next;
// 把反转后的部分接到前面的链表上
pre->next = reverseList(left, right);
// 反转后 left 节点变成反转部分的尾节点,也就是下一段要反转的部分的上一个节点
pre = left;
}
return dummyHead->next;
}
};
struct Node *copyRandomList(struct Node *head) {
if (head == NULL) return NULL;
struct Node *pre = head;
// 遍历原链表,在每个节点后面插入新节点
while (pre != NULL) {
struct Node *node = (struct Node *) malloc(sizeof(struct Node));
node->val = pre->val;
// 接在原节点的后面
node->next = pre->next;
pre->next = node;
pre = pre->next->next;
}
pre = head;
while (pre != NULL) {
// 修改random指针
if (pre->random != NULL)
pre->next->random = pre->random->next;
else
pre->next->random = NULL;
pre = pre->next->next;
}
pre = head;
struct Node *res = head->next, *cur = head->next;
while (cur != NULL && cur->next != NULL) {
// 改回原链表节点的next指针
pre->next = pre->next->next;
pre = pre->next;
// 新链表的节点从原链表中分离出来,串在一起
cur->next = cur->next->next;
cur = cur->next;
}
// 原链表尾节点的next指针
pre->next = NULL;
return res;
}
// 归并
struct ListNode *merge(struct ListNode *l1, struct ListNode *l2) {
if (l1 == NULL || l2 == NULL) return l1 == NULL ? l2 : l1;
struct ListNode *dummyHead = (struct ListNode *) malloc(sizeof(struct ListNode));
struct ListNode *pre = dummyHead;
while (l1 != NULL && l2 != NULL) {
if (l1->val < l2->val) {
pre->next = l1;
l1 = l1->next;
} else {
pre->next = l2;
l2 = l2->next;
}
pre = pre->next;
}
if (l1 != NULL) pre->next = l1;
if (l2 != NULL) pre->next = l2;
return dummyHead->next;
}
struct ListNode *sortList(struct ListNode *head) {
// 统计链表长
int len = 0;
struct ListNode *temp = head;
while (temp != NULL) {
len++;
temp = temp->next;
}
struct ListNode *dummyHead = (struct ListNode *) malloc(sizeof(struct ListNode));
dummyHead->next = head;
// 步长每次乘二
for (int gap = 1; gap < len; gap <<= 1) {
struct ListNode *pre = dummyHead;
struct ListNode *cur = dummyHead->next;
// 每次从一组元素的首个元素节点开始(两个子链表为一组)
while (cur != NULL) {
// 长度为gap的子链表l1
struct ListNode *l1 = cur;
int i = 1;
while (i < gap && cur->next != NULL) {
cur = cur->next;
i++;
}
// 子链表l2
struct ListNode *l2 = cur->next;
// 把l2从l1后面断开
cur->next = NULL;
// 找到子链表l2的末尾,l2可能是最后一个子链表并且长度小于等于gap
// l2后面可能还有
cur = l2;
i = 1;
while (i < gap && cur != NULL && cur->next != NULL) {
cur = cur->next;
i++;
}
struct ListNode *next = NULL;
// l2后面还有节点时
if (cur != NULL) {
// 下一组的起点(两个子链表为一组)
next = cur->next;
// 断开,l2变成完成的一条链表
cur->next = NULL;
}
// 把这组的两个子链表合并
pre->next = merge(l1, l2);
// pre移到合并后的最后一个节点,等待接上下一组合并后的首个节点
while (pre->next != NULL) {
pre = pre->next;
}
// 进入下一组的归并
cur = next;
}
}
return dummyHead->next;
}
class Solution {
public:
// 通过遍历所有链表的头节点,找到每次要合并的节点
ListNode *mergeKLists(vector<ListNode *> &lists) {
// 没有元素直接返回
if (lists.empty()) return nullptr;
ListNode *dummyHead = new ListNode(0, nullptr);
ListNode *pre = dummyHead;
int length = lists.size();
while (true) {
// 记录当前所有链表中头节点值最小的链表在 lists 中的下标
int minHeadIndex = -1;
for (int i = 0; i < length; ++i) {
// 链表非空的情况下,minHeadIndex 为 -1 或者 lists[i] 节点值更小,则更新 minHeadIndex
if ((lists[i] != nullptr) &&
(minHeadIndex == -1 || (lists[i]->val < lists[minHeadIndex]->val)))
minHeadIndex = i;
}
// 已经找不到元素了(链表全都是空的),则函数返回
if (minHeadIndex == -1) return dummyHead->next;
// 否则,移出最小元素,并且合并到最终结果中
ListNode *node = lists[minHeadIndex];
lists[minHeadIndex] = lists[minHeadIndex]->next;
node->next = nullptr;
pre->next = node;
pre = pre->next;
// 判断是否只剩下一条链表
int finished = 0;
for (auto &curHead: lists)
if (curHead == nullptr) finished++;
if (finished >= length - 1) break;
}
// 把最后剩下的一条链表直接接上
for (auto &curHead: lists) {
if (curHead != nullptr) {
pre->next = curHead;
return dummyHead->next;
}
}
return dummyHead->next;
}
};
class Solution {
public:
// 合并两个链表
ListNode *mergeTwoLists(ListNode *a, ListNode *b) {
if ((!a) || (!b)) return a ? a : b;
ListNode *dummyHead = new ListNode(0, nullptr);
ListNode *pre = dummyHead;
ListNode *p = a, *q = b;
while (p && q) {
if (p->val < q->val) {
pre->next = p;
p = p->next;
} else {
pre->next = q;
q = q->next;
}
pre = pre->next;
}
pre->next = (p ? p : q);
return dummyHead->next;
}
// 遍历链表数组,每次把一整条链表和最终结果合并
ListNode *mergeKLists(vector<ListNode *> &lists) {
ListNode *res = nullptr;
for (size_t i = 0; i < lists.size(); ++i)
res = mergeTwoLists(res, lists[i]);
return res;
}
};
class Solution {
public:
// 合并两个链表
ListNode *mergeTwoLists(ListNode *a, ListNode *b) {
if ((!a) || (!b)) return a ? a : b;
ListNode *dummyHead = new ListNode(0, nullptr);
ListNode *pre = dummyHead;
ListNode *p = a, *q = b;
while (p && q) {
if (p->val < q->val) {
pre->next = p;
p = p->next;
} else {
pre->next = q;
q = q->next;
}
pre = pre->next;
}
pre->next = (p ? p : q);
return dummyHead->next;
}
ListNode *merge(vector<ListNode *> &lists, int left, int right) {
if (left > right) return nullptr;
if (left == right) return lists[left];
int mid = (left + right) >> 1;
return mergeTwoLists(merge(lists, left, mid), merge(lists, mid + 1, right));
}
// 分治合并
ListNode *mergeKLists(vector<ListNode *> &lists) {
return merge(lists, 0, lists.size() - 1);
}
};
class Solution {
public:
// 自定义比较函数
static bool cmp(ListNode *a, ListNode *b) {
return (*a).val > (*b).val;
}
// 使用小顶堆,只有初始化堆的时候要遍历一次数组,之后每次把堆顶节点并入最终链表,并且把堆顶节点的后继加入堆中
ListNode *mergeKLists(vector<ListNode *> &lists) {
// 没有元素直接返回
if (lists.empty()) return nullptr;
ListNode *dummyHead = new ListNode(0, nullptr);
ListNode *pre = dummyHead;
// 小顶堆
priority_queue<ListNode *, vector<ListNode *>, decltype(&cmp)> heap(cmp);
// 初始化小顶堆,把所有的链表头节点加入其中
for (auto &curHead: lists) {
if (curHead == nullptr) continue;
heap.push(curHead);
curHead = curHead->next;
}
while (true) {
if (heap.empty() || heap.top() == nullptr) break;
// 取出最小节点,并加入到最终的链表中
ListNode *node = heap.top();
heap.pop();
pre->next = node;
pre = pre->next;
// 如果后面的节点非空的话,就加入到堆中
if (node->next != nullptr) heap.push(node->next);
}
return dummyHead->next;
}
};
// 用hashMap定位节点
class LRUCache {
ListNode dummyHead;
ListNode dummyTail;
int capacity;
Map<Integer, ListNode> map;
public LRUCache(int capacity) {
map = new HashMap<>();
this.capacity = capacity;
dummyHead = new ListNode();
dummyTail = new ListNode();
dummyHead.next = dummyTail;
dummyTail.prev = dummyHead;
}
public int get(int key) {
if (!map.containsKey(key)) return -1;
ListNode node = map.get(key);
moveToHead(node);
return node.value;
}
public void addToHead(ListNode node) {
map.put(node.key, node);
node.next = dummyHead.next;
dummyHead.next.prev = node;
dummyHead.next = node;
node.prev = dummyHead;
}
public void moveToHead(ListNode node) {
// 断开
node.prev.next = node.next;
node.next.prev = node.prev;
// 接上
node.next = dummyHead.next;
dummyHead.next.prev = node;
node.prev = dummyHead;
dummyHead.next = node;
}
public void deleteNode(ListNode node) {
map.remove(node.key);
node.prev.next = node.next;
node.next.prev = node.prev;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
ListNode node = map.get(key);
node.value = value;
moveToHead(node);
return;
}
if (map.size() == capacity) deleteNode(dummyTail.prev);
ListNode node = new ListNode(key, value);
addToHead(node);
}
}
class ListNode {
int key;
int value;
ListNode prev;
ListNode next;
public ListNode(int key, int value, ListNode prev, ListNode next) {
this.key = key;
this.value = value;
this.prev = prev;
this.next = next;
}
public ListNode(int key, int value) {
this.key = key;
this.value = value;
}
public ListNode() {
}
}