2020-6-1
给你一个数组 candies 和一个整数 extraCandies ,其中 candies[i] 代表第 i 个孩子拥有的糖果数目。对每一个孩子,检查是否存在一种方案,将额外的 extraCandies 个糖果分配给孩子们之后,此孩子有 最多 的糖果。注意,允许有多个孩子同时拥有 最多 的糖果数目。
示例 1:
输入:candies = [2,3,5,1,3], extraCandies = 3
输出:[true,true,true,false,true]
解释:
孩子 1 有 2 个糖果,如果他得到所有额外的糖果(3个),那么他总共有 5 个糖果,他将成为拥有最多糖果的孩子。
孩子 2 有 3 个糖果,如果他得到至少 2 个额外糖果,那么他将成为拥有最多糖果的孩子。
孩子 3 有 5 个糖果,他已经是拥有最多糖果的孩子。
孩子 4 有 1 个糖果,即使他得到所有额外的糖果,他也只有 4 个糖果,无法成为拥有糖果最多的孩子。
孩子 5 有 3 个糖果,如果他得到至少 2 个额外糖果,那么他将成为拥有最多糖果的孩子。
示例 2:
输入:candies = [4,2,1,1,2], extraCandies = 1
输出:[true,false,false,false,false]
解释:只有 1 个额外糖果,所以不管额外糖果给谁,只有孩子 1 可以成为拥有糖果最多的孩子。
示例 3:
输入:candies = [12,1,12], extraCandies = 10
输出:[true,false,true]
提示:
2 <= candies.length <= 100
1 <= candies[i] <= 100
1 <= extraCandies <= 50
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
bool* kidsWithCandies(int* candies, int candiesSize, int extraCandies, int* returnSize){
bool* ans=(bool*)malloc(candiesSize*sizeof(bool));
*returnSize=0;
int max=0;
for(int i=0;i<candiesSize;i++){
if(candies[i]>max)max=candies[i];
}
for(int i=0;i<candiesSize;i++){
if(candies[i]+extraCandies>=max)ans[*returnSize]=true;
else ans[*returnSize]=false;
(*returnSize)++;
}
return ans;
}
儿童节快乐☺ ♪ ☑
2020-6-2
求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)
示例 :
输入: n = 9
输出: 45
限制:
1 <= n <= 10000
可以使用的工具:加减法,赋值,位运算符以及逻辑运算符
int sumNums(int n){
if(n==0)return 0;
return n+sumNums(n-1);
}
被限制的方向:递归的条件判断
逻辑运算符的短路性质
以逻辑运算符 & & \&\& && 为例,对于 A & & B A\&\&B A&&B 这个表达式,如果 A 表达式返回 F a l s e False False,那么 A & & B A \&\& B A&&B 已经确定为 F a l s e False False ,此时不会去执行表达式 B。同理,对于逻辑运算符 ||, 对于 A || B 这个表达式,如果 A 表达式返回 T r u e True True ,那么 A || B 已经确定为 T r u e True True ,此时不会去执行表达式 B。
int sumNums(int n){
n&&(n+=sumNums(n-1));
return n;
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
函数指针+两次反运算
typedef unsigned int (*fun)(unsigned int);
unsigned int Teminator(unsigned int n){
return 0;
}
int sumNums(int n){
static fun f[2]={Teminator,sumNums};
return n+f[!!n](n-1); //连续做两次反运算,非零转换为true,0转换为false
}
使用加法和移位运算
乘以2的幂
遍历二进制展开
俄罗斯农民乘法
int quickMulti(int A, int B) {
int ans = 0;
for ( ; B; B >>= 1) {
if (B & 1) {
ans += A;
}
A <<= 1;
}
return ans;
}
手动展开 1414 层代替循环
int sumNums(int n){
int ans = 0, A = n, B = n + 1;
(B & 1) && (ans += A);
A <<= 1; //右移一位 乘2
B >>= 1; //左移一位 除2
(B & 1) && (ans += A);
A <<= 1;
B >>= 1;
(B & 1) && (ans += A);
A <<= 1;
B >>= 1;
(B & 1) && (ans += A);
A <<= 1;
B >>= 1;
(B & 1) && (ans += A);
A <<= 1;
B >>= 1;
(B & 1) && (ans += A);
A <<= 1;
B >>= 1;
(B & 1) && (ans += A);
A <<= 1;
B >>= 1;
(B & 1) && (ans += A);
A <<= 1;
B >>= 1;
(B & 1) && (ans += A);
A <<= 1;
B >>= 1;
(B & 1) && (ans += A);
A <<= 1;
B >>= 1;
(B & 1) && (ans += A);
A <<= 1;
B >>= 1;
(B & 1) && (ans += A);
A <<= 1;
B >>= 1;
(B & 1) && (ans += A);
A <<= 1;
B >>= 1;
(B & 1) && (ans += A);
A <<= 1;
B >>= 1;
return ans >> 1;
}
回顾
2020-6-3
爱丽丝参与一个大致基于纸牌游戏 “21点” 规则的游戏,描述如下:
爱丽丝以 0 分开始,并在她的得分少于 K 分时抽取数字。 抽取时,她从 [1, W] 的范围中随机获得一个整数作为分数进行累计,其中 W 是整数。 每次抽取都是独立的,其结果具有相同的概率。当爱丽丝获得不少于 K 分时,她就停止抽取数字。 爱丽丝的分数不超过 N 的概率是多少?
示例 1:
输入:N = 10, K = 1, W = 10
输出:1.00000
示例 2:
输入:N = 6, K = 1, W = 10
输出:0.60000
示例 3:
输入:N = 21, K = 17, W = 10
输出:0.73278
提示:
0 <= K <= N <= 10000
1 <= W <= 10000
如果答案与正确答案的误差不超过 10^-5,则该答案将被视为正确答案通过。
21点:荷官发牌,你的目的是拿到手上的牌总点数尽可能大。不高于某个值(K)的时候你可以一直叫牌,但万一牌的总点数超过某个值(N)你就爆牌了,此局判负。
那么本题就是在求赢的概率
double new21Game(int N, int K, int W){
double result = 0;
if(K == 0) {
return 1.0;
}
for(int i=1; i<W+1; i++) {
if(i < K) {
double sub = new21Game(N-i, K-i, W);
result += (1/(double)W) * sub;
} else {
if(i <= N) {
result += 1/(double)W;
}
}
}
return result;
}
d p [ x ] dp[x] dp[x]表示从得分为 x x x 的情况开始游戏并且获胜的概率,目标是求 d p [ 0 ] dp[0] dp[0] 的值
状态转移方程:
d p [ x ] = d p [ x + 1 ] + d p [ x + 2 ] + ⋯ + d p [ x + W ] W dp[x]=\frac{dp[x+1]+dp[x+2]+⋯+dp[x+W]}{W} dp[x]=Wdp[x+1]+dp[x+2]+⋯+dp[x+W]
停止抽牌时,最大牌面为 K + W − 1 K+W-1 K+W−1
double new21Game(int N, int K, int W){
double s=0.0;
double *dp=(double*)malloc((K+W)*sizeof(double));
for(int i = K;i < K + W;i++){
if(i <= N){
dp[i]=1;
}else{
dp[i]=0;
}
s=s+dp[i];
}
for(int i = K-1;i >= 0;i--){
dp[i]=s/W;
s = s-dp[i + W]+dp[i];
}
return dp[0];
}
时间复杂度: O ( min ( N , K + W ) ) O(\min(N, K+W)) O(min(N,K+W))
空间复杂度: O ( K + W ) O(K+W) O(K+W)
2020-6-4
给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
示例:
输入: [1,2,3,4]
输出: [24,12,8,6]
提示:题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。
说明: 请不要使用除法
当前数左边乘积*当前数右边乘积
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* productExceptSelf(int* nums, int numsSize, int* returnSize){
*returnSize=0;
int *L=(int *)malloc(numsSize*sizeof(int));
int *R=(int *)malloc(numsSize*sizeof(int));
int *ans=(int *)malloc(numsSize*sizeof(int));
L[0]=1;
R[numsSize-1]=1;
for(int i=1;i<numsSize;i++){
L[i]=L[i-1]*nums[i-1];
}
for(int i=numsSize-2;i>=0;i--){
R[i]=R[i+1]*nums[i+1];
}
for(int i=0;i<numsSize;i++){
ans[i]=L[i]*R[i];
(*returnSize)++;
}
return ans;
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* productExceptSelf(int* nums, int numsSize, int* returnSize){
*returnSize=0;
int *L=(int *)malloc(numsSize*sizeof(int));
L[0]=1;
int R=1;
for(int i=1;i<numsSize;i++){
L[i]=L[i-1]*nums[i-1];
}
for(int i=numsSize-1;i>=0;i--){
L[i]=L[i]*R;
R=R*nums[i];
(*returnSize)++;
}
return L;
}
2020-6-5
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 :
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
限制:
0 <= matrix.length <= 100
0 <= matrix[i].length <= 100
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* spiralOrder(int** matrix, int matrixSize, int* matrixColSize, int* returnSize){
int m=matrixSize; //行
*returnSize=0;
if(m==0)return NULL;
int n=matrixColSize[0]; //列
int *ans=(int *)malloc((m*n)*sizeof(int));
int top=0,bottom=m-1,left=0,right=n-1;
while(left<=right&&top<=bottom){
for (int column = left; column <= right; column++) { //上
ans[(*returnSize)++] = matrix[top][column];
}
for (int row = top + 1; row <= bottom; row++) { //右
ans[(*returnSize)++] = matrix[row][right];
}
if (left < right && top < bottom) {
for (int column = right - 1; column > left; column--) { //下
ans[(*returnSize)++]= matrix[bottom][column];
}
for (int row = bottom; row > top; row--) { //左
ans[(*returnSize)++] = matrix[row][left];
}
}
left++;
right--;
top++;
bottom--;
}
return ans;
}
时间复杂度: O ( m n ) O(mn) O(mn)
空间复杂度: O ( 1 ) O(1) O(1)
2020-6-6
给定一个未排序的整数数组,找出最长连续序列的长,要求算法的时间复杂度为 O(n)。
示例:
输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
struct hashNode {
int key;
struct hashNode *next;//冲突时,用指针连接
};
struct hashMap {
int size;
struct hashNode *data;
};
struct hashMap * hashCreat(int size)
{
//新建一个哈希表
struct hashMap * hashMapInfo;
//为哈希表分配地址
hashMapInfo = (struct hashMap *)malloc(sizeof(struct hashMap));
//设置哈希表的大小
hashMapInfo->size = size;
//为哈希表的data部分分配地址
hashMapInfo->data = (struct hashNode *)malloc(sizeof(struct hashNode) * size);
//初始化哈希表每个哈希节点的对象
for (int i = 0; i < size; i++) {
hashMapInfo->data[i].key = INT_MIN;
hashMapInfo->data[i].next = NULL;
}
return hashMapInfo;
}
//将键为key的节点放入到哈希表中
void Put(int key, struct hashMap * hashMapInfo)
{
//计算节点的位置
int pos = abs(key) % hashMapInfo->size;
//定义哈希节点,其值为 key所在位置的数据的链表地址
struct hashNode *data = &hashMapInfo->data[pos];
//定义一个新的哈希节点,为空
struct hashNode *newNode = NULL;
if (data->key == INT_MIN) { //链表未占用
data->key = key;
return;
}
while (data != NULL) {//while循环要考虑当前节点,不能从data->next开始
if (data->key == key) { //当前链表已存在该key,直接返回不插入
return;
}
if (data->next == NULL) { //为后续添加Node做准备
break;
}
data = data->next; //链表next节点
}
/* 添加节点 */
newNode = (struct hashNode *)malloc(sizeof(struct hashNode));
newNode->key = key;
newNode->next = NULL;
data->next = newNode;
return;
}
//查找
bool Contain(long key, struct hashMap * hashMapInfo)
{
//计算节点的位置
int pos;
if(key==INT_MIN)pos = abs(INT_MAX) % hashMapInfo->size;
else pos = abs(key) % hashMapInfo->size;
//定义哈希节点,其值为 key所在位置的数据的链表地址
struct hashNode *data = &hashMapInfo->data[pos];
if (data->key == INT_MIN) { //链表未占用
return false;
}
while (data != NULL) {//while循环要考虑当前节点,不能从data->next开始
if (data->key == key) { //当前链表已存在该key
return true;
}
data = data->next; //链表next节点
}
return false;
}
int longestConsecutive(int* nums, int numsSize){
struct hashMap *hashMapInfo;
hashMapInfo=hashCreat(numsSize);
for(int i=0;i < numsSize;i++) {
//printf("TTTT\n");
Put(nums[i], hashMapInfo);
}
int longestStreak = 0;
for (int i=0;i<numsSize;i++) {
if (!Contain(nums[i]-1,hashMapInfo)) { //前一个数不存在,那我此数即为序列第一个
int currentNum = nums[i];
int currentStreak = 1;
while (Contain(currentNum + 1,hashMapInfo)) {
currentNum += 1;
currentStreak += 1;
}
longestStreak = fmax(longestStreak, currentStreak);
}
}
return longestStreak;
}
https://leetcode-cn.com/problems/longest-consecutive-sequence/solution/bing-cha-ji-ting-qi-lai-nan-shi-ji-yi-dian-du-bu-n/
下次一定
回顾
Line 35: Char 37: runtime error: member access within null pointer of type 'struct hashMap' (solution.c)
Line 72: Char 15: runtime error: negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself (solution.c)
2020-6-8
给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:“a==b” 或 “a!=b”。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。
示例 1:
输入:[“a==b”,“b!=a”]
输出:false
解释:如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。
示例 2:
输出:[“b==a”,“a==b”]
输入:true
解释:我们可以指定 a = 1 且 b = 1 以满足满足这两个方程。
示例 3:
输入:[“a==b”,“b==c”,“a==c”]
输出:true
示例 4:
输入:[“a==b”,“b!=c”,“c==a”]
输出:false
示例 5:
输入:[“c==c”,“b==d”,“x!=z”]
输出:true
提示:
1 <= equations.length <= 500
equations[i].length == 4
equations[i][0] 和 equations[i][3] 是小写字母
equations[i][1] 要么是 ‘=’,要么是 ‘!’
equations[i][2] 是 ‘=’
并查集
#define MAXN 26
int fa[MAXN];
//初始化
void init(int n)
{
for (int i = 0; i < n; ++i){
fa[i] = i;
}
}
//查询
int find(int x)
{
if(fa[x] == x)
return x;
else
return find(fa[x]);
}
//合并
void merge(int i, int j)
{
fa[find(i)] = find(j);
}
bool equationsPossible(char ** equations, int equationsSize){
init(MAXN);
for(int i=0;i<equationsSize;i++){
if(equations[i][1]=='='){
int index1=equations[i][0]-'a';
int index2=equations[i][3]-'a';
merge(index1,index2);
}
}
for(int i=0;i<equationsSize;i++){
if(equations[i][1]=='!'){
int index1=equations[i][0]-'a';
int index2=equations[i][3]-'a';
if (find(index1) == find(index2)) {
return false;
}
}
}
return true;
}
2020-6-9
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", “bwfi”, “bczi”, “mcfi"和"mzi”
提示:
0 < = n u m < 2 31 0 <= num < 2^{31} 0<=num<231
d p [ i ] dp[i] dp[i]: x i x_i xi为开头的数字的翻译方案数量
d p [ i ] = d p [ i + 1 ] + g ( i , i + 1 ) ∗ d p [ i + 2 ] dp[i]=dp[i+1]+g(i,i+1)*dp[i+2] dp[i]=dp[i+1]+g(i,i+1)∗dp[i+2]
从后往前计算
int translateNum(int num){
if(num<0)return 0;
if(num==0)return 1;
int count[11];
int n=0; //位数
//从低位到高位存储数字中每一位数
int number[11];
int temp=num,i=0;
while(temp){
int complement=temp%10;
temp=temp/10;
n++;
number[i++]=complement;
}
//翻转,从高位到低位
int Number[11];
for(int i=0;i<n;i++){
Number[i]=number[n-i-1];
}
if(n==1)return 1; //个位数直接输出
//计算后两位
count[n-1]=1;
int two=Number[n-2]*10+Number[n-1];
if((two>=10)&&(two<=25))count[n-2]=2;
else count[n-2]=1;
for(int i=n-3;i>=0;i--){
two=Number[i]*10+Number[i+1];
int g;
if((two>=10)&&(two<=25))g=1;
else g=0;
if(i<n-1){
count[i]=count[i+1]+g*count[i+2];
}
}
return count[0];
}
d p [ i ] dp[i] dp[i]: x i x_i xi为结尾的数字的翻译方案数量
d p [ i ] = d p [ i − 1 ] + g ( i , i − 1 ) ∗ d p [ i − 2 ] dp[i] = dp[i - 1] + g(i,i-1)*dp[i - 2] dp[i]=dp[i−1]+g(i,i−1)∗dp[i−2]
初始状态: d p [ 0 ] = d p [ 1 ] = 1 dp[0] = dp[1] = 1 dp[0]=dp[1]=1
返回值: d p [ n ] dp[n] dp[n]
int translateNum(int num){
if(num<0)return 0;
if(num==0)return 1;
int count[11];
int n=0; //位数
//从低位到高位存储数字中每一位数
int number[11];
int temp=num,i=0;
while(temp){
int complement=temp%10;
temp=temp/10;
n++;
number[i++]=complement;
}
//翻转,从高位到低位
int Number[11];
for(int i=0;i<n;i++){
Number[i]=number[n-i-1];
}
if(n==1)return 1; //个位数直接输出
count[0]=1;
int two=Number[0]*10+Number[1];
if((two>=10)&&(two<=25))count[1]=2;
else count[1]=1;
for(int i=2;i<n;i++){
int two=Number[i]+Number[i-1]*10;
int g;
if((two>=10)&&(two<=25))g=1;
else g=0;
count[i]=count[i-1]+g*count[i-2];
}
return count[n-1];
}
边取余边计算
d p [ i ] = d p [ i + 1 ] + g ( i , i + 1 ) ∗ d p [ i + 2 ] dp[i]=dp[i+1]+g(i,i+1)*dp[i+2] dp[i]=dp[i+1]+g(i,i+1)∗dp[i+2]
d p [ i ] dp[i] dp[i]: x i x_i xi开头的数字的翻译方案数量,从后往前计算
int translateNum(int num){
if(num<0)return 0;
if(num==0)return 1;
int dp0=1; //dp[i]
int dp1=1; //dp[i+1]
int dp2=1; //dp[i+2]
int n1; //第i位
int n2=num%10; //第i+1位
while(num){
num=num/10;
n1=num%10;
int two=10*n1+n2;
if((two>=10)&&(two<=25))dp0=dp1+dp2;
else dp0=dp1;
//向左移动
dp2=dp1;
dp1=dp0;
n2=n1;
}
return dp0;
}
2020-6-10
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例 1:
输入: 121
输出: true
示例 2:
输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
bool isPalindrome(int x){
if(x==0)return true;
if(x<0)return false;
int num[12],n=0,i=0;
while(x){
num[i]=x%10;
x=x/10;
n++;
i++;
}
for(int j=0,k=n-1;j<=k;j++,k--){
if(num[j]!=num[k])return false;
}
return true;
}
bool isPalindrome(int x){
if(x == 0)return true;
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}
int revertedNumber = 0;
while (x > revertedNumber) {
revertedNumber = revertedNumber * 10 + x % 10;
x = x / 10;
}
// 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。
// 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,
// 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。
return x == revertedNumber || x == revertedNumber / 10;
}
2020-6-10
请判断一个链表是否为回文链表,用 O(n) 时间复杂度和 O(1) 空间复杂度
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool isPalindrome(struct ListNode* head){
if(!head || !head->next)
return true;
struct ListNode *fast = head, *slow = head;
struct ListNode *p, *pre = NULL;
while(fast && fast->next){
p = slow;
slow = slow->next; //快慢遍历
fast = fast->next->next;
p->next = pre; //翻转
pre = p;
//printf("pre=%d,p=%d,slow=%d,fast=%d\n",pre->val,p->val,slow->val,fast->val);
}
if(fast) //奇数个节点时跳过中间节点
slow = slow->next;
while(p){ //前半部分和后半部分比较
if(p->val != slow->val)
return false;
p = p->next;
slow = slow->next;
}
return true;
}
void reverse(struct ListNode* head){
struct ListNode *h=head;
while(h!=NULL){
printf("%d ",h->val);
h=h->next;
}
printf("\n");
struct ListNode *temp = head;
struct ListNode *p, *pre = NULL;
while(temp!=NULL){
if(pre!=NULL)printf("pre=%d ",pre->val);
if(p!=NULL)printf("p=%d ",p->val);
if(temp!=NULL)printf("temp=%d ",temp->val);
printf("\n");
p = temp;
temp=temp->next;
p->next = pre; //翻转
pre = p;
}
while(p!=NULL){
printf("%d ",p->val);
p=p->next;
}
while(pre!=NULL){
printf("%d ",pre->val);
pre=pre->next;
}
}
2020-6-11
根据每日气温列表,请重新生成一个列表,对应位置的输出是需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* dailyTemperatures(int* T, int TSize, int* returnSize){
*returnSize=0;
int *ans=(int *)malloc(TSize*sizeof(int));
for(int i=0;i<TSize;i++){
int num=0;
for(int j=i+1;j<TSize;j++){
if(T[j]>T[i]){
num=j-i;
break;
}
}
ans[i]=num;
(*returnSize)++;
}
return ans;
}
时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( 1 ) O(1) O(1)
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* dailyTemperatures(int* T, int TSize, int* returnSize){
*returnSize=0;
int *ans=(int *)malloc(TSize*sizeof(int));
for(int s=0;s<TSize;s++){
ans[s]=0;
}
int next[101]={0};
for(int i=0;i<101;i++){
next[i]+=INT_MAX;
}
for (int i = TSize - 1; i >= 0; --i) {
int warmerIndex = INT_MAX;
for (int t = T[i] + 1; t <= 100; ++t) {
warmerIndex = fmin(warmerIndex, next[t]);
}
if (warmerIndex != INT_MAX) {
ans[i] = warmerIndex - i;
}
next[T[i]] = i;
(*returnSize)++;
}
return ans;
}
时间复杂度: O ( n m ) O(nm) O(nm)
空间复杂度: O ( m ) O(m) O(m)
#define MaxSize 30000
typedef struct Stack{
int top;
int num[MaxSize];
}Stack;
Stack S;
void init(){
S.top=0;
}
void push(int a){
S.top++;
S.num[S.top]=a;
}
int pop(){
if(S.top==0)return 0;
S.top--;
return S.num[S.top+1];
}
int Top(){
return S.num[S.top];
}
int empty(){
if(S.top==0)return 1;
else return 0;
}
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* dailyTemperatures(int* T, int TSize, int* returnSize){
init();
*returnSize=0;
int *ans=(int *)malloc(TSize*sizeof(int));
for(int s=0;s<TSize;s++){
ans[s]=0;
}
for(int i=0;i<TSize;i++){
while(!empty()&&T[Top()]<T[i]){
int index=Top();
ans[index]=i-index;
pop();
}
push(i);
(*returnSize)++;
}
return ans;
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
回顾
我初始化数组时像个人工智障 稍后再看
//数组初始化实在是头疼
int *ans=(int *)malloc(TSize*sizeof(int));
for(int s=0;s<TSize;s++){
ans[s]=0;
}
int next[101]={0};
for(int i=0;i<101;i++){
next[i]+=INT_MAX;
}
2020-6-12
三数之和之前搞过了,整个类似的四数之和回忆一下:D
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等,找出所有满足条件且不重复的四元组。答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[[-1, 0, 0, 1],[-2, -1, 1, 2],[-2, 0, 0, 2]]
/**
* Return an array of arrays of size *returnSize.
* The sizes of the arrays are returned as *returnColumnSizes array.
* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
*/
int compInc(const void *a, const void *b) //递增
{
return *(int *)a - *(int *)b;
}
int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes){
*returnSize = 0; // 参数returnSize用来作为二维数组行数下标的指针
if (numsSize < 4)
{
return NULL;
}
qsort(nums, numsSize, sizeof(int), compInc);
int maxSize=numsSize*10;
int** returnArray = (int**)malloc(sizeof(int*) * maxSize);
*returnColumnSizes = (int*)malloc(sizeof(int) * maxSize);
for(int i=0;i<numsSize-3;i++){
for(int j=i+1;j<numsSize-2;j++){
int L=j+1,R=numsSize-1;
while(L<R){
int sum=nums[i]+nums[j]+nums[L]+nums[R];
if(sum==target){
returnArray[*returnSize] = (int*)malloc(sizeof(int) * 4);
(*returnColumnSizes)[*returnSize] = 4;
returnArray[*returnSize][0] = nums[i];
returnArray[*returnSize][1] = nums[j];
returnArray[*returnSize][2] = nums[L];
returnArray[*returnSize][3] = nums[R];
(*returnSize)++;
while (nums[L + 1] == nums[L] &&(L+1)< R)
{
L++;
}
while (nums[R - 1] == nums[R] && L < (R-1))
{
R--;
}
L++;
R--;
}
else if(sum<target){
L++;
}
else if(sum>target){
R--;
}
}
while(nums[j]==nums[j+1]&&j<numsSize-2){
j++;
}
}
while(nums[i]==nums[i+1]&&i<numsSize-3){
i++;
}
}
return returnArray;
}
时间复杂度: O ( n 3 ) O(n^3) O(n3)
2020-6-13
爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] dp[i]=dp[i-1]+dp[i-2] dp[i]=dp[i−1]+dp[i−2]
int climbStairs(int n){
if(n==1)return 1;
if(n==2)return 2;
int dp1=1,dp2=2,dp=0;
for(int i=3;i<=n;i++){
//printf("dp1= %d dp2= %d dp= %d\n",dp1,dp2,dp);
dp=dp1+dp2;
dp1=dp2;
dp2=dp;
}
return dp;
}
使用最小花费爬楼梯
数组的每个索引作为一个阶梯,第 i个阶梯对应着一个非负数的体力花费值 c o s t [ i ] cost[i] cost[i](索引从0开始)。每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯。您需要找到达到楼层顶部的最低花费。在开始时,你可以选择从索引为 0 或 1 的元素作为初始阶梯。
示例 1:
输入: cost = [10, 15, 20]
输出: 15
解释: 最低花费是从cost[1]开始,然后走两步即可到阶梯顶,一共花费15。
示例 2:
输入: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
输出: 6
解释: 最低花费方式是从cost[0]开始,逐个经过那些1,跳过cost[3],一共花费6。
注意:
cost 的长度将会在 [2, 1000]。
每一个 cost[i] 将会是一个Integer类型,范围为 [0, 999]。
d p [ i ] = c o s t [ i ] + m i n ( d p [ i + 1 ] , d p [ i + 2 ] ) dp[i] = cost[i] + min(dp[i+1], dp[i+2]) dp[i]=cost[i]+min(dp[i+1],dp[i+2])
d p [ i ] dp[i] dp[i]表示从第 i i i个阶梯开始爬并经过第 i i i个阶梯,需要的最小花费
int minCostClimbingStairs(int* cost, int costSize){
int dp1 = 0, dp2 = 0;
for (int i = costSize - 1; i >= 0; --i) {
int dp0 = cost[i] + fmin(dp1, dp2);
dp2 = dp1;
dp1 = dp0;
}
return fmin(dp1, dp2);
}
d p [ i ] = c o s t [ i ] + m i n ( d p [ i − 1 ] , d p [ i − 2 ] ) dp[i] = cost[i] + min( dp[i-1] , dp[i-2] ) dp[i]=cost[i]+min(dp[i−1],dp[i−2])
d p [ i ] dp[i] dp[i]表示第 i i i 级阶梯的总花费 = 第 i i i 级的 c o s t cost cost + 前两级阶梯的总花费的较小者
//dp[i] = cost[i] + min(dp[i-1], dp[i-2])
int minCostClimbingStairs(int* cost, int costSize){
int dp1 = 0, dp2 = 0;
for (int i = 0; i < costSize; i++) {
int dp0 = cost[i] + fmin(dp1, dp2);
dp2 = dp1;
dp1 = dp0;
}
return fmin(dp1, dp2);
}
d p [ n ] = m i n ( d p [ n − 1 ] + c o s t [ n − 1 ] , d p [ n − 2 ] + c o s t [ n − 2 ] ) dp[n] = min(dp[n-1] + cost[n-1], dp[n-2] + cost[n-2]) dp[n]=min(dp[n−1]+cost[n−1],dp[n−2]+cost[n−2])
初始可以选择第0或第1个阶梯,所以 d p [ 0 ] = 0 , d p [ 1 ] = 0 dp[0]=0,dp[1]=0 dp[0]=0,dp[1]=0,题目就是要求出 d p [ c o s t S i z e ] dp[costSize] dp[costSize]
int minCostClimbingStairs(int* cost, int costSize){
int *dp=(int *)malloc((costSize+1)*sizeof(int));
dp[0]=0;
dp[1]=0;
for (int i = 2; i < costSize+1; i++) {
dp[i]= fmin(dp[i-2]+ cost[i-2], dp[i-1] + cost[i-1]);
}
return dp[costSize];
}
2020-6-15
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例 1:
输入: [“flower”,“flow”,“flight”]
输出: “fl”
示例 2:
输入: [“dog”,“racecar”,“car”]
输出: “”
解释: 输入不存在公共前缀。
char * longestCommonPrefix(char ** strs, int strsSize){
int n=10000;
for(int i=0;i<strsSize;i++){
if(n>strlen(strs[i]))n=strlen(strs[i]);
}
char *ans=(char *)malloc((n+1)*sizeof(char));
int s=0;
if(strsSize==0)
{
ans[s]='\0';
return ans;
}
for(int j=0;j<n;j++){
for(int k=0;k<strsSize-1;k++){
if(strs[k][j]!=strs[k+1][j]){
ans[s]='\0';
return ans;
}
}
ans[s]=strs[0][j];
s++;
}
ans[s]='\0';
return ans;
}
官方题解给了四种方法:纵向、横向、分治、二分,但从解题角度来讲,纵向就挺好,又快。还有一个字典树,下次一定。
2020-6-16
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
/** Encodes a tree to a single string. */
#define MAX_SIZE 100000
#define STR_SIZE 10
void pre_order(struct TreeNode *root, char * data){ //前序遍历
if(root == NULL){
strcat(data, "#");
strcat(data, ",");
return;
}
char tmp[STR_SIZE] = "";
sprintf(tmp, "%d", root->val); // 把结果输出到字符串tmp中
strcat(data, tmp);
strcat(data, ",");
pre_order(root->left, data);
pre_order(root->right, data);
}
char* serialize(struct TreeNode* root) {
char * ans = malloc(sizeof(char) * MAX_SIZE);
memset(ans, '\0', sizeof(char) * MAX_SIZE);
pre_order(root, ans);
return ans;
}
struct TreeNode * createTree(char *data, int *index){
if(data[*index] == '#'){
(*index)++; // ‘#’
(*index)++; // ‘,’
return NULL;
}
struct TreeNode * root = malloc(sizeof(struct TreeNode));
char tmp[STR_SIZE] = "";
int k = 0;
while(data[*index] != ','){
tmp[k++] = data[*index];
(*index)++;
}
(*index)++; // 因为此时data[*index] = ','
root->val = atoi(tmp); // 获取数值
root->left = createTree(data, index); // 递归左子树
root->right = createTree(data, index); // 递归右子树
return root;
}
/** Decodes your encoded data to tree. */
struct TreeNode* deserialize(char* data) {
int index = 0; // index表示数组下标,不需要回溯
return createTree(data, &index);
}
// Your functions will be called as such:
// char* data = serialize(root);
// deserialize(data);
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
/** Encodes a tree to a single string. */
#define MaxSize 100000
typedef struct queue {
struct TreeNode* data[MaxSize];
int front;
int rear;
}Queue;
void initilize(Queue *Q) {
Q->front = 0;
Q->rear = 0;
}
void Push(struct TreeNode* root,Queue *Q) {
Q->data[++Q->rear] = root;
}
struct TreeNode* Pop(Queue *Q) {
return Q->data[++Q->front];
}
struct TreeNode* Top(Queue *Q) {
return Q->data[Q->front];
}
int empty(Queue *Q) {
return Q->rear == Q->front;
}
char* serialize(struct TreeNode* root) {
Queue * Q=(Queue*)malloc(sizeof(Queue));
initilize(Q);
struct TreeNode *cur= (struct TreeNode*) calloc (1, sizeof(struct TreeNode));
char *ans=(char *)malloc(MaxSize*sizeof(char));
ans[0]='\0'; 为方便使用strcat
char tmp[10] = "";
if (root == NULL) return 0; //空树
Push(root,Q);
sprintf(tmp, "%d", root->val);
strcat(ans, tmp);
strcat(ans, ",");
while (!empty(Q)) {
cur = Pop(Q);
if(cur->left == NULL){
strcat(ans, "*");
strcat(ans, ",");
}else{
sprintf(tmp, "%d", cur->left->val);
strcat(ans, tmp);
strcat(ans, ",");
Push(cur->left,Q);
}
if(cur->right == NULL){
strcat(ans, "*");
strcat(ans, ",");
}else{
sprintf(tmp, "%d", cur->right->val);
strcat(ans, tmp);
strcat(ans, ",");
Push(cur->right,Q);
}
}
//输出转换后的序列
int t=0;
while(ans[t]!='\0'){
printf("%c ",ans[t]);
t++;
}
return ans;
}
2020-6-17
给定正整数数组 A A A, A [ i ] A[i] A[i]表示第 i i i个观光景点的评分,并且两个景点$ i $和 j j j 之间的距离为 j − i j - i j−i。一对景点 ( i < j ) (i < j) (i<j)组成的观光组合的得分为 ( A [ i ] + A [ j ] + i − j ) (A[i] + A[j] + i - j) (A[i]+A[j]+i−j):景点的评分之和减去它们两者之间的距离。返回一对观光景点能取得的最高分。
示例:
输入:[8,1,5,2,6]
输出:11
解释:i = 0, j = 2, A[i] + A[j] + i - j = 8 + 5 + 0 - 2 = 11
提示:
2 <= A.length <= 50000
1 <= A[i] <= 1000
A [ i ] + A [ j ] + i − j → ( A [ i ] + i ) + ( A [ j ] − j ) A[i] + A[j] + i - j\rightarrow (A[i] + i)+(A[j] - j) A[i]+A[j]+i−j→(A[i]+i)+(A[j]−j)
int maxScoreSightseeingPair(int* A, int ASize){
int ans = 0, mx = A[0] + 0;
for (int j = 1; j < ASize; ++j) {
ans = fmax(ans, mx + A[j] - j);
mx = fmax(mx, A[j] + j);
}
return ans;
}
2020-6-18
我们从二叉树的根节点 root 开始进行深度优先搜索。
在遍历中的每个节点处,我们输出 D 条短划线(其中 D 是该节点的深度),然后输出该节点的值。(如果节点的深度为 D,则其直接子节点的深度为 D + 1。根节点的深度为 0)。
如果节点只有一个子节点,那么保证该子节点为左子节点。
给出遍历输出 S,还原树并返回其根节点 root。
循环 | level | value | length | pop | action | push | stack |
---|---|---|---|---|---|---|---|
1 | 0 | 1 | 0 | - | - | 1 | 1 |
2 | 1 | 2 | 1 | - | 1 − > l e f t = 2 1->left=2 1−>left=2 | 2 | 1 2 |
3 | 2 | 3 | 2 | - | 2 − > l e f t = 3 2->left=3 2−>left=3 | 3 | 1 2 3 |
4 | 2 | 4 | 3 | 3 | 2 − > r i g h t = 4 2->right=4 2−>right=4 | 4 | 1 2 4 |
5 | 1 | 5 | 3 | 4 2 | 1 − > r i g h t = 5 1->right=5 1−>right=5 | 5 | 1 5 |
6 | 2 | 6 | 2 | - | 5 − > l e f t = 6 5->left=6 5−>left=6 | 6 | 1 5 6 |
7 | 2 | 7 | 1 | 6 | 5 − > r i g h t = 7 5->right=7 5−>right=7 | 7 | 1 5 7 |
8 | - | - | - | 7 5 | - | - | 1 |
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
#define MaxSize 100000
typedef struct Stack {
struct TreeNode* data[MaxSize];
int top;
}Stack;
Stack S;
void Initilize() {
S.top=0;
}
void Push(struct TreeNode* root) {
S.top++;
S.data[S.top]=root;
}
struct TreeNode* Pop() {
S.top--;
return S.data[S.top+1];
}
struct TreeNode* Top() {
return S.data[S.top];
}
int Empty() {
return S.top==0;
}
int Length(){
return S.top;
}
struct TreeNode* recoverFromPreorder(char * S){
int n=strlen(S);
Initilize();
for(int i=0;i<n;){
int level=0;
while(S[i]=='-'){ //计算每一个节点的深度
i++;
level++;
}
// printf("level: %d ",level);
int value=0;
while(i<n&&isdigit(S[i])){ //计算节点的数字,需要逐位翻译
value=value*10+(int)(S[i]-'0');
i++;
}
//printf("value: %d ",value);
struct TreeNode* node=malloc(sizeof(struct TreeNode));
node->val=value;
node->left=NULL;
node->right=NULL;
//printf("length: %d ",Length());
if(level==Length()){
if(!Empty()){
Top()->left=node;
}
}else{
while(level!=Length()){
Pop();
}
Top()->right=node;
}
Push(node);
}
while(Length()>1){
Pop();
}
return Top();
}
2020-6-19
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: “A man, a plan, a canal: Panama”
输出: true
示例 2:
输入: “race a car”
输出: false
bool isPalindrome(char * s){
int n=strlen(s);
//printf("%d",n);
if(n==0)return true;
for(int i=0;i<n;i++){
if(s[i]>='A'&&s[i]<='Z'){
s[i]=s[i]+32;
printf("%c ",s[i]);
}
}
for(int left=0,right=n-1;left<right;left++,right--){
//printf("left: %d,right: %d \n",left,right);
while(!((s[left]>='0'&&s[left]<='9')||(s[left]>='a'&&s[left]<='z'))&&left<right){
left++;
}
while(!((s[right]>='0'&&s[right]<='9')||(s[right]>='a'&&s[right]<='z'))&&left<right){
right--;
}
if(s[left]!=s[right]){
return false;
}
}
return true;
}
特殊的测试用例
"" //空字符串
",.," //不含有数字字母的字符串
回顾
2020-6-21
给定一个非空二叉树,返回其最大路径和。
本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
int maxGain(struct TreeNode *root,int *maxValue){
if(root==NULL){
return 0;
}
int leftGain=fmax(maxGain(root->left,maxValue),0);
int rightGain=fmax(maxGain(root->right,maxValue),0);
int curValue=root->val+leftGain+rightGain;
//printf("curValue: %d maxValue: %d\n",curValue,*maxValue);
*maxValue=fmax(*maxValue,curValue);
return root->val+fmax(leftGain,rightGain);
}
int maxPathSum(struct TreeNode* root)
{
int maxValue = INT_MIN; // 最小值
maxGain(root, &maxValue);
return maxValue;
}
2020-6-23
给你两个二进制字符串,返回它们的和(用二进制表示)。
输入为 非空 字符串且只包含数字 1 和 0。
示例 1:
输入: a = “11”, b = “1”
输出: “100”
示例 2:
输入: a = “1010”, b = “1011”
输出: “10101”
//翻转字符串
void reserve(char* s) {
int len = strlen(s);
for (int i = 0; i < len / 2; i++) {
char t = s[i];
s[i] = s[len - i - 1], s[len - i - 1] = t;
}
}
char* addBinary(char* a, char* b) {
reserve(a);
reserve(b);
int len_a = strlen(a), len_b = strlen(b);
int n = fmax(len_a, len_b), carry = 0, len = 0;
char* ans = (char*)malloc(sizeof(char) * (n + 2));
for (int i = 0; i < n; ++i) {
carry += i < len_a ? (a[i] == '1') : 0;
carry += i < len_b ? (b[i] == '1') : 0;
ans[len++] = carry % 2 + '0';
carry /= 2;
}
if (carry) {
ans[len++] = '1';
}
ans[len] = '\0'; //重要操作
reserve(ans);
return ans;
}
半成品代码
void reserve(char* s) {
int len = strlen(s);
printf("len: %d ",len);
for (int i = 0; i < len / 2; i++) {
char t = s[i];
s[i] = s[len - i - 1];
s[len - i - 1] = t;
}
}
char * addBinary(char * a, char * b){
int n1=strlen(a);
int n2=strlen(b);
int A=0;
int B=0;
int ans,carry;
//字符串转化为整数
for(int i=0;i<n1;i++){
A=A*10+a[ i ]-'0';
}
for(int i=0;i<n2;i++){
B=B*10+b[ i ]-'0';
}
while(B){
ans=(A ^ B);
carry=(A & B) << 1;
A=ans;
B=carry;
}
//整数转化为字符串
int i=0;
char* Ans=malloc((fmax(n1,n2)+2)*sizeof(char));
while(ans != 0){
Ans[ i ]=ans % 10+'0';
i++;
ans=ans/10;
}
Ans[i]='\0'; //重要操作
reserve(Ans);
return Ans;
}
2020-6-24
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
示例:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
提示:
3 < = n u m s . l e n g t h < = 1 0 3 3 <= nums.length <= 10^3 3<=nums.length<=103
− 1 0 3 < = n u m s [ i ] < = 1 0 3 -10^3 <= nums[i] <= 10^3 −103<=nums[i]<=103
− 1 0 4 < = t a r g e t < = 1 0 4 -10^4 <= target <= 10^4 −104<=target<=104
与三数之和相同
int compInc(const void *a, const void *b) //递增
{
return *(int *)a - *(int *)b;
}
int threeSumClosest(int* nums, int numsSize, int target){
int error=INT_MAX,ans;
qsort(nums, numsSize, sizeof(int), compInc);
for(int i=0;i<numsSize;i++){
int L=i+1;
int R=numsSize-1;
while(L<R){
int sum=nums[i]+nums[L]+nums[R];
if(sum==target){
return target;
}
if(fabs(sum-target)<error){
error=fabs(sum-target);
ans=sum;
}
if(sum<target){
while(nums[L]==nums[L+1]&&(L+1)<R){
L++;
}
L++;
}else{
while(nums[R]==nums[R-1]&&L<(R-1)){
R--;
}
R--;
}
}
}
return ans;
}
2020-6-27
给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
示例 1: 输入: [1,2,0] 输出: 3
示例 2: 输入: [3,4,-1,1] 输出: 2
示例 3: 输入: [7,8,9,11,12] 输出: 1
提示:
你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。
关键思路
对于一个长度为 N N N 的数组,其中没有出现的最小正整数只能在 [ 1 , N + 1 ] [1, N+1] [1,N+1] 中。这是因为如果 [ 1 , N ] [1, N] [1,N] 都出现了,那么答案是 N + 1 N+1 N+1,否则答案是 [ 1 , N ] [1, N] [1,N] 中没有出现的最小正整数
我的抄答案版本
int firstMissingPositive(int* nums, int numsSize){
int* NUM=malloc(numsSize*sizeof(int));
for(int i=0;i<numsSize;i++){
NUM[i]=i+1;
}
for(int i=0;i<numsSize;i++){
if(nums[i]<=0){
nums[i]=numsSize+1;
}
}
for(int j=0;j<numsSize;j++){
if(nums[j]<=numsSize&&NUM[nums[j]-1]>0){
NUM[nums[j]-1]=-NUM[nums[j]-1];
}
}
for(int k=0;k<numsSize;k++){
if(NUM[k]>0)return NUM[k];
}
return numsSize+1;
}
官方题解版本,不新建数组
int firstMissingPositive(int* nums, int numsSize) {
for (int i = 0; i < numsSize; ++i) {
if (nums[i] <= 0) {
nums[i] = numsSize + 1;
}
}
for (int i = 0; i < numsSize; ++i) {
int num = abs(nums[i]);
if (num <= numsSize) {
nums[num - 1] = -abs(nums[num - 1]);
}
}
for (int i = 0; i < numsSize; ++i) {
if (nums[i] > 0) {
return i + 1;
}
}
return numsSize + 1;
}
对数组进行一次遍历,对于遍历到的数 x = n u m s [ i ] x=nums[i] x=nums[i],如果 x ∈ [ 1 , N ] x∈[1,N] x∈[1,N],我们就知道 x x x 应当出现在数组中的 x − 1 x−1 x−1 的位置,因此交换 n u m s [ i ] nums[i] nums[i] 和 n u m s [ x − 1 ] nums[x−1] nums[x−1],这样 x x x 就出现在了正确的位置。在完成交换后,新的 n u m s [ i ] nums[i] nums[i] 可能还在 [ 1 , N ] [1, N] [1,N] 的范围内,我们需要继续进行交换操作,直到 x ∉ [ 1 , N ] x \notin [1, N] x∈/[1,N]
如果 n u m s [ i ] nums[i] nums[i] 恰好与 n u m s [ x − 1 ] nums[x−1] nums[x−1] 相等,那么就会无限交换下去。此时我们有 n u m s [ i ] = x = n u m s [ x − 1 ] nums[i]=x=nums[x−1] nums[i]=x=nums[x−1],说明 x x x 已经出现在了正确的位置。因此我们可以跳出循环,开始遍历下一个数。
由于每次的交换操作都会使得某一个数交换到正确的位置,因此交换的次数最多为 N N N,整个方法的时间复杂度为 O ( N ) O(N) O(N)
int firstMissingPositive(int* nums, int numsSize) {
for (int i = 0; i < numsSize; ++i) {
while (nums[i] > 0 && nums[i] <= numsSize &&
nums[nums[i] - 1] != nums[i]) {
int t = nums[nums[i] - 1];
nums[nums[i] - 1] = nums[i], nums[i] = t;
}
}
for (int i = 0; i < numsSize; ++i) {
if (nums[i] != i + 1) {
return i + 1;
}
}
return numsSize + 1;
}
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的连续子数组,返回 0。
示例:
输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
2020-6-28
int minSubArrayLen(int s, int* nums, int numsSize){
if(numsSize==0)return 0;
int ans=INT_MAX;
for(int i=0;i<numsSize;i++){
int sum=0;
for(int j=i;j<numsSize;j++){
sum=sum+nums[j];
int count=j-i+1;
printf("sum= %d count= %d\n",sum,count);
if(sum>=s&&count<ans){
ans=count;
break;
}
}
}
if(ans==INT_MAX)ans=0;
return ans;
}
时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( 1 ) O(1) O(1)
int minSubArrayLen(int s, int* nums, int numsSize) {
if (numsSize == 0) {
return 0;
}
int ans = INT_MAX;
int L=0,R=0,sum=0;
while(R<numsSize){
sum+=nums[R];
while(sum>=s){
ans=fmin(ans,R-L+1);
sum-=nums[L];
L++;
}
R++;
}
return ans == INT_MAX ? 0 : ans;
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)
int lower_bound(int *a, int l, int r, int q) {
if (a[r] < q) return -1;
while (l < r) {
int mid = (l + r) >> 1;
if (a[mid] >= q) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
int minSubArrayLen(int s, int *nums, int numsSize) {
if (numsSize == 0) {
return 0;
}
int ans = INT_MAX;
int *sums = (int *)malloc(sizeof(int) * (numsSize + 1));
// 为了方便计算,令 size = n + 1
// sums[0] = 0 意味着前 0 个元素的前缀和为 0
// sums[1] = A[0] 前 1 个元素的前缀和为 A[0]
// 以此类推
for (int i = 1; i <= numsSize; i++) {
sums[i] = sums[i - 1] + nums[i - 1];
}
for (int i = 1; i <= numsSize; i++) {
int target = s + sums[i - 1];
int bound = lower_bound(sums, 1, numsSize, target);
if (bound != -1) {
ans = fmin(ans, bound - (i - 1));
}
}
return ans == INT_MAX ? 0 : ans;
}
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
空间复杂度: O ( n ) O(n) O(n)
2020-6-29
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
int findKthLargest(int* nums, int numsSize, int k){
for(int i=numsSize-1;i>=numsSize-k;i--){
for(int j=0;j<i;j++){
if(nums[j]>nums[j+1]){
int t=nums[j];
nums[j]=nums[j+1];
nums[j+1]=t;
}
}
}
return nums[numsSize-k];
}
//严奶奶版本快排
int Partition(int *A,int low,int high){
int key=A[low];
while(low < high){
while(low < high && A[high] >= key){
high--;
}
int t=A[low];
A[low]=A[high];
A[high]=t;
while(low < high && A[low] <= key){
low++;
}
t=A[low];
A[low]=A[high];
A[high]=t;
}
A[low]=key;
return low;
}
void QSort(int* A,int low,int high){
if(low<high){
int piv=Partition(A,low,high);
QSort(A,low,high-1);
QSort(A,low+1,high);
}
}
int findKthLargest(int* nums, int numsSize, int k){
QSort(nums,0,numsSize-1);
for(int i=0;i < numsSize;i++){
printf("%d ",nums[i]);
}
return nums[numsSize-k];
}
//算法导论版本快排
int Partition(int* a, int l, int r) {
int x = a[r], i = l - 1;
for (int j = l; j < r; ++j) {
if (a[j] <= x) {
int t = a[++i];
a[i] = a[j], a[j] = t;
}
}
int t = a[i + 1];
a[i + 1] = a[r], a[r] = t;
return i + 1;
}
int quickSelect(int* a, int l, int r, int index) {
int q = Partition(a, l, r);
if (q == index) {
return a[q];
} else {
return q < index ? quickSelect(a, q + 1, r, index): quickSelect(a, l, q - 1, index);
}
}
int findKthLargest(int* nums, int numsSize, int k) {
return quickSelect(nums, 0, numsSize - 1, numsSize - k);
}
随机选择主元:随机选择一个元素与A[r]交换
inline int partition(int* a, int l, int r) {
int x = a[r], i = l - 1;
for (int j = l; j < r; ++j) {
if (a[j] <= x) {
int t = a[++i];
a[i] = a[j], a[j] = t;
}
}
int t = a[i + 1];
a[i + 1] = a[r], a[r] = t;
return i + 1;
}
inline int randomPartition(int* a, int l, int r) {
int i = rand() % (r - l + 1) + l;
int t = a[i];
a[i] = a[r], a[r] = t;
return partition(a, l, r);
}
int quickSelect(int* a, int l, int r, int index) {
int q = randomPartition(a, l, r);
if (q == index) {
return a[q];
} else {
return q < index ? quickSelect(a, q + 1, r, index)
: quickSelect(a, l, q - 1, index);
}
}
int findKthLargest(int* nums, int numsSize, int k) {
srand(time(0));
return quickSelect(nums, 0, numsSize - 1, numsSize - k);
}
void maxHeapify(int* a, int i, int heapSize) {
int l = i * 2 + 1, r = i * 2 + 2, largest = i;
if (l < heapSize && a[l] > a[largest]) {
largest = l;
}
if (r < heapSize && a[r] > a[largest]) {
largest = r;
}
if (largest != i) {
int t = a[i];
a[i] = a[largest], a[largest] = t;
maxHeapify(a, largest, heapSize);
}
}
void buildMaxHeap(int* a, int heapSize) {
for (int i = heapSize / 2; i >= 0; --i) {
maxHeapify(a, i, heapSize);
}
}
int findKthLargest(int* nums, int numsSize, int k) {
int heapSize = numsSize;
buildMaxHeap(nums, heapSize);
for (int i = numsSize - 1; i >= numsSize - k + 1; --i) {
int t = nums[0];
nums[0] = nums[i], nums[i] = t;
--heapSize;
maxHeapify(nums, 0, heapSize);
}
return nums[0];
}
2020-6-30
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
示例 1:
输入:
[“CQueue”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[3],[],[]]
输出:[null,null,3,-1]
示例 2:
输入:
[“CQueue”,“deleteHead”,“appendTail”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[],[5],[2],[],[]]
输出:[null,-1,null,null,5,2]
提示:
1 <= values <= 10000
最多会对 appendTail、deleteHead 进行 10000 次调用
#define MaxSize 10000
typedef struct {
int data1[MaxSize];
int data2[MaxSize];
int top1;
int top2;
} CQueue;
CQueue* cQueueCreate() {
CQueue* obj=malloc(sizeof(CQueue));
obj->top1=0;
obj->top2=0;
return obj;
}
void cQueueAppendTail(CQueue* obj, int value) {
obj->top1++;
obj->data1[obj->top1]=value;
}
int cQueueDeleteHead(CQueue* obj) {
if(obj->top2!=0){
obj->top2--;
return obj->data2[obj->top2+1];
}
while(obj->top1!=0){
//出栈
int t=obj->data1[obj->top1];
obj->top1--;
//进栈
obj->top2++;
obj->data2[obj->top2]=t;
}
if(obj->top2==0)return -1;
obj->top2--;
return obj->data2[obj->top2+1];
}
void cQueueFree(CQueue* obj) {
free(obj);
obj = NULL;
}
/**
* Your CQueue struct will be instantiated and called as such:
* CQueue* obj = cQueueCreate();
* cQueueAppendTail(obj, value);
* int param_2 = cQueueDeleteHead(obj);
* cQueueFree(obj);
*/
函数功能:格式化字符串,将格式化的数据写入字符串中。
函数原型:
int sprintf(char *buffer, const char *format, [argument]...)
// buffer:是char类型的指针,指向写入的字符串指针
// format:格式化字符串,即在程序中想要的格式
// argument:可选参数,可以为任意类型的数据
函数返回值:buffer指向的字符串的长度;
sprintf函数的使用
C语言中sprintf()函数的用法
头文件:
#include
#include
声明:
char *strcat(char *dest, const char *src)
参数:
功能:
把src所指字符串添加到dest结尾处(覆盖dest结尾处的’\0’)并添加’\0’
C字符串操作strcat/strcat_s详解