c语言 -我与letcode相爱相杀
有人相爱,有人夜里开车看海,有人leetcode第一题都做不出来。
1.两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
解决方法:
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
int i,j=0,len,sum=0;
len = numsSize;
//创建一个新数组
int *result =NULL;
result = (int *)malloc(sizeof(int)*2);
while(j<len-1){
for(i=j+1;i<len;i++){
sum = nums[j]+nums[i];
if(sum==target){
result[0]=j;
result[1]=i;
*returnSize=2;
return result;
}else{
sum=0;
}
}
j++;
}
//返回长度
*returnSize=0;
return result;
}
9.回文数
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
例如,121 是回文,而 123 不是。
示例:
输入:x = 121
输出:true
解决方法:
bool isPalindrome(int x){
int x1=x;
long int y=0;
if(x<0)
return false;
while(x!=0){
y=x%10+y*10;
x=x/10;
}
if(x1==y)
return true;
return false;
}
13.罗马数字转整数
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。
输入: s = "III"
输出: 3
解决方法:
int rback(char ch);
int romanToInt(char *s){
int sum=0;
int len =strlen(s);
for(int i=0;i<len;i++){
if(i!=len-1){
if(s[i]=='I'){
if(s[i+1]=='V'||s[i+1]=='X')//你只管继续加,我只管我自己的减
sum =sum-2;
}else if(s[i]=='X'){
if(s[i+1]=='L'||s[i+1]=='C')//你只管继续加,我只管我自己的减
sum =sum-20;
}else if(s[i]=='C'){
if(s[i+1]=='D'||s[i+1]=='M')//你只管继续加,我只管我自己的减
sum =sum-200;
}
}
sum =sum+rback(s[i]);
}
return sum;
}
int rback(char ch){
switch(ch) {
case 'I': return 1;
case 'V': return 5;
case 'X': return 10;
case 'L': return 50;
case 'C': return 100;
case 'D': return 500;
case 'M': return 1000;
case 'a': return 4;
case 'b': return 9;
case 'c': return 40;
case 'd': return 90;
case 'e': return 400;
case 'f': return 900;
}
return 0;
}
26. 删除有序数组中的重复项
给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。
将最终结果插入 nums 的前 k 个位置后返回 k 。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
示例:
输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
解决方法:
int removeDuplicates(int* nums, int numsSize){
int i=0;
if(numsSize<=1)
return numsSize;
for(int j=1;j<numsSize;j++){
if(nums[i]!=nums[j]){
nums[++i]=nums[j];
}
}
return i+1;
}
27. 移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例:
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
解决方法:
int removeElement(int* nums, int numsSize, int val){
int j=0;
for(int i =0;i<numsSize;i++){
if(nums[i]!=val){
nums[j++]=nums[i];
}
}
return j;
}
35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
示例:
输入: nums = [1,3,5,6], target = 5
输出: 2
解决方法:
int searchInsert(int* nums, int numsSize, int target){
int i;
for(i=0;i<numsSize;i++){
if(nums[i]>=target){
return i;
}
}
return i;
}
58. 最后一个单词的长度
给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。
单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。
示例:
输入:s = "Hello World"
输出:5
解释:最后一个单词是“World”,长度为5。
解决方法:
int lengthOfLastWord(char * s){
int i,count=0,flag=0;
int len = strlen(s);
for(i=len-1;i>=0;i--){//从后往前数
if(s[i]==' '){
if(flag==0)
count=0;
else
break;
}else{
count++;
flag=1;
}
}
return count;
}
20. 有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
1.左括号必须用相同类型的右括号闭合。
2.左括号必须以正确的顺序闭合。
3.每个右括号都有一个对应的相同类型的左括号。
输入:s = "()[]{}"
输出:true
解决方法:
用数组模拟栈
char *s;
int top=-1;
if(top==-1)//栈为空先输入
s[top]=temp;
//入栈
top++;
s[top]=temp;
//出栈
top--;
bool isValid(char * s){
int i;
int temp;
int top = -1;//栈的标值
int len = strlen(s);
for(i=0;i<len;i++){
temp =s[i];
if(top == -1){//栈为空时
top++;
s[top] = temp;
}else{
//( [ { 入栈
if(temp=='('||temp=='['||temp=='{'){
top++;
s[top] = temp;
}else {
if(temp==')'){
if(s[top]=='(')
top--;
else
return false;
}else if(temp==']'){
if(s[top]=='[')
top--;
else
return false;
}else if(temp=='}'){
if(s[top]=='{')
top--;
else
return false;
}
}
}
}
if(top==-1){
return true;
}
return false;
}
70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
示例 :
输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1 阶 + 1 阶 + 1 阶
1 阶 + 2 阶
2 阶 + 1 阶
解决方法:
第n个台阶只能从第n-1或者n-2个上来。
到第n-1个台阶的走法 + 第n-2个台阶的走法 = 到第n个台阶的走法,已经知道了第1个和第2个台阶的走法,一路加上去。
1阶->1 2阶->2(1 1/2) 3阶->1阶+2阶 3 4阶->3阶+2阶 5
int climbStairs(int n){
if(n==1)
return 1;
if(n==2)
return 2;
int a=1,b=2,temp;
for(int i=3;i<=n;i++){
temp=a;
a=b;
b=temp+a;
}
return b;
}
605.种花问题
假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false。
输入:flowerbed = [1,0,0,0,1], n = 2
输出:false
解决方法:
bool canPlaceFlowers(int* flowerbed, int flowerbedSize, int n){
//保证他左边没花,右边也没花
int i;
int num=0;
for(i=0;i<flowerbedSize;i++){
if(flowerbed[i]==0&&(i==0||flowerbed[i-1]!=1)&&(i+1==flowerbedSize||flowerbed[i+1]!=1)){//种花
flowerbed[i]=1;
num++;//最多种
}
}
return num>=n;
}
860. 柠檬水找零
在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。
每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。
注意,一开始你手头没有任何零钱。
给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。
输入:bills = [5,5,10,10,20]
输出:false
解释:
前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。
对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。
对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。
由于不是每位顾客都得到了正确的找零,所以答案是 false。
解决方法:
bool lemonadeChange(int* bills, int billsSize){
int i;
int num5=0,num10=0,num20=0;
int flag=0;
if(bills[0]==5){
num5++;
}else{
return false;
}
for(i=1;i<billsSize;i++){
if(bills[i]==5){
num5++;
}else if(bills[i]==10){
if(num5>0){
num5--;
num10++;
}else
flag=1;
}else if(bills[i]==20){
if(num10>0&&num5>0){//用一张10和一张5还
num20++;
num10--;
num5--;
}else if(num5>=3){//用三张五还
num20++;
num5=num5-3;
}else
flag=1;
}
}
if(flag==1)
return false;
else
return true;
}
1323.6和9组成的最大数字
给你一个仅由数字 6 和 9 组成的正整数 num。
你最多只能翻转一位数字,将 6 变成 9,或者把 9 变成 6 。
请返回你可以得到的最大数字。
输入:num = 9996
输出:9999
解释:将最后一位从 6 变到 9,其结果 9999 是最大的数。
解决方法:
int maximum69Number (int num){
//把第一个遇到的6变为9;
int a[100];
//先求数值长度
int num1=num;
int len=0;
while(num1>0){
len++;
num1=num1/10;
}
num1=num;
int i,j;
for(i=len-1;i>=0;i--){
a[i]=num1%10;
num1=num1/10;
}
i=0;
num1=len;
while(len>0){
if(a[i]==6){
a[i]=9;
break;
}
i++;
len--;
}
len=num1;
int chen=1;
int sum=0;
for(i=len-1;i>=0;i--){
sum=sum+a[i]*chen;
chen=chen*10;
}
return sum;
}
55.跳跃游戏
给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
解决方法:
计算每个方格能到达最远的距离,只要能超出数组长度,就可以跳出
bool canJump(int* nums, int numsSize){//在该位置可以跳跃的最大长度
int i=0;
int len=0;//能到的最远距离
if(numsSize<=1)
return true;
while(i<=len){//动态规划
if(i+nums[i]>=numsSize-1)
return true;
else if(i+nums[i]>len)
len = i+nums[i];
i++;
}
return false;
}
122. 买卖股票的最佳时机 II
给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。总利润为 4 。
解决方法:
算法题(×) 脑筋急转弯题( √ )
扫描一遍 只要后一天比前一天大 就把这两天的差值加一下
int maxProfit(int* prices, int pricesSize){//你能获得的最大利润 ->只要一直保证有得赚就行
int ans=0;
for(int i=1;i<pricesSize;i++){
if(prices[i]>prices[i-1]){
ans+=prices[i]-prices[i-1];
}
}
return ans;
}
674. 最长连续递增序列
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。
输入:nums = [1,3,5,4,7]
输出:3
解释:最长连续递增序列是 [1,3,5], 长度为3。
尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。
解决方法:
int findLengthOfLCIS(int* nums, int numsSize){//找递增序列
int dp[numsSize];
int i;
for(i=0;i<numsSize;i++){
dp[i]=1;
}
for(i=1;i<numsSize;i++){//动态规划
if(nums[i]>nums[i-1]){
dp[i]=dp[i-1]+1;
}
}
int max=0;
for(i=0;i<numsSize;i++){
if(max<dp[i])
max=dp[i];
}
return max;
}
198. 打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
解决方法:
我是一个专业的小偷,小偷看了看这几个屋子里的钱,哭笑不得,于是把身上仅带的200块钱分给了这几个屋子的主人们,扬长而去。
int rob(int* nums, int numsSize){//动态规划在于数组不断变化
int money[numsSize];
if(numsSize<=1)
return numsSize==0?0:nums[0];
int i;
money[0]=nums[0];
money[1]=fmax(nums[0],nums[1]);
for(i=2;i<numsSize;i++){//i=2;money[2]=max(money[1],nums[2]+money[0])
money[i]=fmax(money[i-1],nums[i]+money[i-2]);//[2,7,9,3,1] i=3;money[3]=max(money[2],nums[3]+money[1])
}
return money[numsSize-1];
}