LeetCode 方法详解

本文详细介绍了LeetCode中的算法,包括罗马数字转换、括号生成、二叉搜索树等题目,结合实例进行了解析,并提供了DFS深度优先搜索等解题方法。
摘要由CSDN通过智能技术生成
1:两个数的和为一个定值
题目描述:给一个序列,找到两个数的和为给定的值,返回这两个数的索引。
题目解析:
(1)暴力法:i从0...n-1;j从i+1...n。如果两个数的和等于给定值,就返回索引。时间复杂度高O(n^2)
(2)排序+扫描:将数组排序,然后i指针后移,j指针左移,直到找到两个数的和等于给定值。时间复杂度O(n logn)
(3)空间换时间:a+b = target。也就是在数组中找target - a。先将数组扫描一遍,建立一个hash表,然后再扫描数组,判断target-arr[i]是否在hash表中。 时间复杂度O(n)。

2:找到两个有序数组的中间值,但时间复杂度要是O(log(m+n))
题目解析:
(1)暴力法,但不满足题意
(2)二分查找+递归:比如A[m]和B[n]数组。我们找第k大的数的时候,就用A[k/2-1]和B[k/2-1]比较,如果是小于号,证明A的前k/2的数据都在合并后的数组的前半区。然后递归进行处理!

3、找出最长不连续的子串
题目描述:"abcabcbb"中"abc"最长。
题目解析:可以理解成一个滑动窗口,滑动窗口内的字符不重复,求最大的窗口大小。
(1)暴力法:以每一个字符为起点,向右遍历,找到最大的长度。
(2)哈希表:我们用一个26个字符的数组来表示该字符是否出现过。但这就带来了一个问题,abcbdef,当遍历到第2个b的时候,a数据应该清除掉的。那么这个时候,我们就用两个指针,i慢,j快。当发现重复的时候,就i++并且清楚hash表的相应位。
(3)哈希表:我们可以用26个字符的数组来存储该字符的位置。当发现重复的时候,就要将位置赋值成新的位置,但是其他位置要如何修改?由于len增加的时候是一个一个增加,而减小的时候,可以大幅度一次性减小。可以利用len = min(len+1,j-index)来推测新值。

4、两个链表相加
题目描述:将一个数的每一位用链表的形式存储,现在要将两个数相加,求得最后的结果。
题目解析:就是简单相应的位相加,要注意进位。L1->data 、L2->data和carryover三个数相加,分两次运行,这样就不用同时满足L1和L2都不为空。简化代码的实现。

5、最长回文子串
题目解析:
(1)暴力法:起始位置为i,让j从i+1到n遍历,针对每一个j判断i--j是否是回文字符串。O(n^3)
(2)动态规划:p[i,j] = (s[i] == s[j]) && p[i+1,j-1];
(3)中心扩展法:以每一个字符为中心,向两边扩展。注意要分奇偶扩展。
(4)Manacher算法:O(n)

6、锯齿形转换
题目解析:
(1)通过数学分析找出规律,每行都有哪些元素坐标。
(2)用c++的容器,可以添加元素,就不用专门设数组。按照上下遍历即可。

7、翻转整数
题目描述:将123变化成321,-123变化成-321
题目解析:
转换的思路倒不难,但是关于存储数据的方式一定要整理清楚:
(1)unsigned int temp = (unsigned int)n;必须要强制类型转换。
(2)输出数据的时候要用%u来输出无符号数据
(3)对于一个整数每一位进行描述,我们要么转化成字符串进行处理,要么通过数组来表示

8、回文数字
题目解析:
(1)我们可以判断最高位和判断最低位是否相等,若相等,则去掉高位和去掉低位,剩余的数据再判断是不是回文数
(2)可以利用翻转来解决,当然这里要注意溢出的问题,不过我们可以用longlong类型,定义更大的数据,然后reverse = 10*reverse+curNum%10;  
curNum /= 10; 最后,判断reverse == curNum。
(3)将整数转换成字符串或者数组来表示,然后用前后指针来判断是否相等。
(4)通过《左旋转字符串》得到启发,我们可以将"54322345"拆分成"5432"和"2345",然后将其中一个翻转,判断两个数是否相等。

9、装最多的水
题目描述:arr[n]的数组中,第i个位置的线的高度为arr[i],任取两条线,求能装的最大容量。
题目解析:
(1)暴力方法:分别以每条线为起点,求得最大的容量。
(2)两个指针:i...j。求得体积后,小的边向多方移动一位,求面积更新。
(3)优化方案二:i....j。求得体积后,让小的边向对方移动,直到找到比它大的边停止,求值更新;再移动小的边……

10:整数转换为罗马数字
题目解析:
对于一个整数,我们需要从高位向低位一点一点转换,由于罗马数字是有对应关系的,我们通过数组来表示即可。
  1.     int value[] = {1000,900,500,400,100,90,50,40,10,9,5,4,1};  
  2.     char *roman[] = { "M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};  
  3.     char store[20] = {0};  
  4.   
  5.     int len = sizeof(value)/sizeof(int);  
  6.     for(int i = 0;i < len;++i){  
  7.         while(n >= value[i]){  
  8.             n -= value[i];  
  9.             strcat(store,roman[i]);  
  10.         }  
  11.     }  


11、罗马数字转换成整数
题目解析:
这里求解的时候要从罗马数字的低位向高位移动,碰到相应的字母就转换成相应的数字。但对于"IX"我们有10-1=9。也就是当str[i] < str[i+1]时,减去str[i]表示的数字。
  1.     arr['I'-'A'] = 1;  
  2.     arr['V'-'A'] = 5;  
  3.     arr['X'-'A'] = 10;  
  4.     arr['L'-'A'] = 50;  
  5.     arr['C'-'A'] = 100;  
  6.     arr['D'-'A'] = 500;  
  7.     arr['M'-'A'] = 1000;  
  8.   
  9.     result = arr[str[n-1]-'A'];  
  10.     for(int i = n-2;i >= 0;--i){  
  11.         if(arr[str[i]-'A'] >= arr[str[i+1]-'A'])  
  12.             result = result + arr[str[i]-'A'];  
  13.         else  
  14.             result = result - arr[str[i]-'A'];  
  15.     }  

12、最长公共前缀
一系列字符串中,两两比较,找到最短的前缀。

13、号码的字符串组合
题目解析:
深度优先遍历的典型引用。对于每一个字符所代表的数字遍历,然后递归到下一个字符。
注意区别什么时候当前递归函数中需要加for循环,什么时候不需要加。当前字符有多重可能的时候,就for循环表示。

14、移除链表中倒数第n个结点
题目解析:
很简单,但要注意输入参数的判断、链表个数以及临界条件。

15、括号匹配
题目解析:
给定一个由左右括号组成的字符串,判断是否是匹配的。通过一个栈来实现,左括号就入栈,右括号时与出栈元素向匹配。
当然当匹配到最后的时候,还要判断栈是否为空,如果不为空也是匹配失败。

16、生成括号
题目解析:
(1)深度优先算法:
利用标记数组来标记哪些还没访问过。找到第一个没有被访问的位置i,然后在i+1,i+3,i+4....位置放置右括号。但是要注意,如果在j放了右括号后,j+1已经右括号了,就不再向右判断了!否则会出现重复的现象。
当退出当前循环的时候,第i的位置要清零。
  1. void DFS(int *visited,char *buf,int n)  
  2. {  
  3.     int i;  
  4.     for(i = 0;i < n;i++){  
  5.         if(visited[i] == 0)  
  6.             break;  
  7.     }  
  8.     if(i == n){  
  9.         puts(buf);  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值