LeetCode
来源:互联网 发布:华3交换机端口激活命令 编辑:程序博客网 时间:2024/05/22 06:29
前言
前一段时间在刷leetcode的习题,刷了100道题,但是并没有很深刻的感觉(可能是因为自己陷入了为了刷题而刷题的状态中,忘了思考了)。按照自己一贯做事的方案,如果没有很深刻的感觉,那就适时的进行总结。回顾曾走过的路,让自己走的更踏实些。
我准备对所刷题目的解答进行汇总。对每一个题目我首先提供我自己的一些解法思路,也有有可能加入一些别人精彩的思路。考虑到工程量的浩大,可能并不会事事巨细。这个仅仅是我自己的浅薄的总结,不到之处,还请大家批评指正。
为了阅读方便,我将按照题目编号顺序写出解答。注意:这些解答在leetcode上通过,但并不表明它们是没有bug的,如果大家发现了bug,欢迎大家指正。
对于每一个题目,我将按照如下的模式进行阐述。
- 题目编号. 标题
- 题目内容
- 题意: 中文简单分析
- 思路: 1. 2. 3. …
- 代码: 简单想法+代码
- 注意: 额外的注意事项
1. Two Sum
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution.
Example:Given nums = [2, 7, 11, 15], target = 9,Because nums[0] + nums[1] = 2 + 7 = 9,return [0, 1].
题意:给定一个int型数组以及一个target,得到两个元素的下标使得这两个元素的和等于target。
思路:
- n个元素,两两一组,一共有n*(n-1)/2组,可在O(n^2)的时间复杂度上得出结果。
- 更优一点的方案,首先进行排序,然后对n个元素,按顺序选择。如果选择的某一个元素array[i],且i为结果,那么target-array[i]也必在数组中。因此将问题转换为查找target-array[i]的问题,由于已排序,那么可采用二分查找。总的时间复杂度为排序时间+逐个尝试并查找时间 = O(nlgn) + O(nlgn) = O(nlgn).
- 上面其实给出了另外的hash的思路。首先将数组中的所有元素存入hash表中,然后选择数组的一个元素array[i],判断target-array[i]是否也在数组中,这相当于判断是否在hash表中。总的时间复杂度为O(n) + O(n) = O(n).
- 我并没有想到其他更优的方案,因为根据直觉来看,至少需要O(n)的时间复杂度,因为任何一个元素都有可能成为结果,我们至少对每个元素要查看一次。
代码:
只给出hash思想的代码。首先对所有的元素构建hash,然后查找target-array[i]在hash表中是否存在。同时为了返回结果中的索引,在存入hash的时候同时存入元素的索引。
vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int, int> umi; for(int i = 0; i < nums.size(); ++i){ umi[nums[i]] = i; } for(int i = 0; i < nums.size(); ++i){ auto it = umi.find(target-nums[i]); if(it != umi.end() && it->second != i){ return {i, it->second}; } } return {};}
注意:
上面的代码有一个小的技巧。为什么要判断it->second != i? 考虑array = [2 2 3], target=4: 这样hash表中只有一个元素,当find(target-nums[i])的时候,肯定会找到2,但是这个2可能是nums[i]对应的索引,而不是target-nums[i]对应的索引。
2. Add Two Numbers
You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)Output: 7 -> 0 -> 8
题意: 两个非负数相加求和。与普通的求和不一样的是,这两个数是由链表存储的。例如上面的342+465=807,并将结果也存入链表中返回。
思路:
1. 遍历链表,分别得到两个int变量,然后相加,并将结果转换为链表
2. 两个链表同时遍历,遍历的过程就是累加的过程。由于链表本身存储就是先低位再高位的形式,因此可以直接相加求和即可,注意进位。
代码: 两个链表同时遍历,相加,进位,同时注意链表长度可能不一样,先到尾部的链表相当于后面补0.也就是说342+65 = 342 + 065 = 407
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { ListNode tmp(0); ListNode *p = &tmp; int high = 0; while(l1 || l2){ int cur = ((l1) ? l1->val : 0) + ((l2) ? l2->val:0) + high; if(cur >= 10){ high = 1; cur -= 10; }else{ high = 0; } ListNode* q = new ListNode(cur); p->next = q; p = q; if(l1) l1 = l1->next; if(l2) l2 = l2->next; } if(high){ p->next = new ListNode(high); } return tmp.next;}
注意: 上面代码有两个讨巧之处。 第一个是tmp节点的使用,这个是额外的链表头节点,利用这个节点可以减少head==NULL这样的判断; 第二个是(l1) ? l1->val : 0这样的用法,如果节点有效,则使用其val,否则使用0,这样就可以不同长度的两个链表的操作统一化了。当然也可以不这样做,当其中某一个链表为空的时候,就停止while循环,然后将不空的链表直接接到已经求得的链表尾部即可,特别类似于两个有序链表的合并问题。
6. ZigZag Conversion
The string “PAYPALISHIRING” is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
P A H NA P L S I I GY I R
And then read line by line: “PAHNAPLSIIGYIR”
Write the code that will take a string and make this conversion given a number of rows:
string convert(string text, int nRows);
convert(“PAYPALISHIRING”, 3) should return “PAHNAPLSIIGYIR”.
题意: 将一个字符串竖着排成一个之字形,然后按照行序输出。
思路:
1. 此题目很简单,肯定是O(n)时间复杂度,将列序转为行序的即可。关键是分析之字形,发现其行数比斜线的个数多2个。
2.
代码: 代码很简单,就是简单定义numRows个字符串,然后遍历输入字符串,逐个塞入到对应的行字符串中,首先处理一列numRows个字符,再处理斜线的numRows-2个字符。
string convert(string s, int numRows) { int i = 0; vector<string> vs(numRows); while(i < s.size()){ for(int j = 0; j < numRows && i <s.size(); ++j){ vs[j].push_back(s[i++]); } for(int j = numRows-2; j >=1 && i < s.size(); --j){ vs[j].push_back(s[i++]); } } string res; for(auto i : vs){ //printf("%s\n", i.c_str()); res += i; } return res;}
注意: 没啥可注意的,代码简单清晰。
7. Reverse Integer
Reverse digits of an integer.
Example1: x = 123, return 321Example2: x = -123, return -321
题意: int变量的反转
思路:
1. 先转为字符串,再字符串反转
2. 逐个得出数,并进行乘10加即可。
代码:简单易懂,res= res*10 + c这个很常用,注意记忆。
int reverse(int x) { if(x == 0) return 0; int minus = 1; if(x < 0){ minus = -1; x = -x; } long xx = x, res = 0; char c; while(xx){ c = xx % 10; res = res * 10 + c; //printf("%d ", c); xx /= 10; } res *= minus; if(res > std::numeric_limits<int>::max() || res < std::numeric_limits<int>::min() ) return 0; return res;}
注意: int反转可能导致导致越界,此处我将x转换为long型的xx,再进行的处理,其实这个地方的做法有些多余,只需要将res定义为long类型,不需要xx就行。
不断追加中
- leetcode
- [leetcode]
- LeetCode
- leetcode
- leetcode
- leetcode:
- leetcode:
- LeetCode
- leetcode
- LEETCODE
- leetcode
- leetCode
- leetcode
- [leetcode]
- LeetCode
- leetcode
- leetcode:
- leetcode
- Java enum的用法详解
- iOS EXC_BAD_ACCESS 的处理方法
- ios学习路线—iOS高级(NSThread)
- mysql(一)
- CentOS关闭图形界面(x window)
- LeetCode
- UIview需要知道的一些事情:setNeedsDisplay、setNeedsLayout
- C语言常见错误
- 用FireDAC连接oracle(接近直连)
- Linux 常用到的功能及命令-FAQ
- VLAN基本通信原理
- 点击listView中的图片,在HorizontalScrollView显示出来,在点击item,图片消失
- 练习四 1003
- PCL 1.7.2 All-in-one Installer MSVC2012 x64