(每题第一个代码仅供参考,后面是官方题解)
1.两数之和
题目:
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6 输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6 输出:[0,1]
提示:
-
2 <= nums.length <= 104 -
-109 <= nums[i] <= 109 -
-109 <= target <= 109 -
只会存在一个有效答案
思路:
1.暴力枚举:拿到一个x遍历数组找target-x,使用两个for循环,外层循环是拿x,并且x之前的元素已经和x匹配过,那么内层循环我们只需要使用x之后的元素匹配target-x
class Solution {
public int[] twoSum(int[] nums, int target) {
int n = nums.length;
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (nums[i] + nums[j] == target) {
return new int[]{i, j};
}
}
}
return new int[0];
}
}
2.哈希表
创建一个哈基表,遍历数组元素,访问当前元素x时,首先查找哈希表中是否存在target-x,如果存在,则返回下标,否则将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();
for (int i = 0; i < nums.length; ++i) {
if (hashtable.containsKey(target - nums[i])) {
return new int[]{hashtable.get(target - nums[i]), i};
}
hashtable.put(nums[i], i);
}
return new int[0];
}
}
2.回文数
题目
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false
回文数
是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
-
例如,
121是回文,而123不是。
示例 1:
输入:x = 121 输出:true
示例 2:
输入:x = -121 输出:false 解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:
输入:x = 10 输出:false 解释:从右向左读, 为 01 。因此它不是一个回文数。
提示:
-
-231 <= x <= 231 - 1
思路
1.将数字转换为字符串,检查字符串是否为回文
class Solution {
public boolean isPalindrome(int x) {
int j=0,flag=0;
if(x<0)
return false;
String str= String.valueOf(x);
for(int i=str.length()-1;i>(str.length()-1)/2;i--){
if (str.charAt(j)!=str.charAt(i)){
flag=1;
break;
}
j++;
}
if(flag==0)
return true;
else
return false;
}
}
2.将数字翻转,翻转后的数字与原始数字进行比较,但是要注意整数溢出的问题
进阶:可以只翻转数字的一半,既可以避免溢出又能提高效率
class Solution {
public boolean isPalindrome(int x) {
// 特殊情况:
// 如上所述,当 x < 0 时,x 不是回文数。
// 同样地,如果数字的最后一位是 0,为了使该数字为回文,
// 则其第一位数字也应该是 0
// 只有 0 满足这一属性
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}
int revertedNumber = 0;
while (x > revertedNumber) {
revertedNumber = revertedNumber * 10 + x % 10;
x /= 10;
}
// 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。
// 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,
// 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。
return x == revertedNumber || x == revertedNumber / 10;
}
}
3.罗马数字转整数
题目
罗马数字包含以下七种字符: 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。
给定一个罗马数字,将其转换成整数。
示例 1:
输入: s = "III" 输出: 3
示例 2:
输入: s = "IV" 输出: 4
示例 3:
输入: s = "MCMXCIV" 输出: 1994 解释: M = 1000, CM = 900, XC = 90, IV = 4.
提示:
-
1 <= s.length <= 15
思路
1.从左到右累加,如果遇到特殊的规则即小的数字在大的数字的左边的情况,则相减,也可以将每个字符视作一个单独的值,若一个数字右侧的数字比它大,则将该数字的符号取反。
class Solution {
public int romanToInt(String s) {
int count=0;
for(int i=0;i<s.length();i++){
if((i+1)!=s.length() && get(s.charAt(i))<get(s.charAt(i+1))){
count+=get(s.charAt(i+1))-get(s.charAt(i));
i++;
}
else count+=get(s.charAt(i));
}
return count;
}
public int get(char c){
switch (c) {
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;
default:
return 0;
}
}}
//官方题解
class Solution {
private:
unordered_map<char, int> symbolValues = {
{'I', 1},
{'V', 5},
{'X', 10},
{'L', 50},
{'C', 100},
{'D', 500},
{'M', 1000},
};
public:
int romanToInt(string s) {
int ans = 0;
int n = s.length();
for (int i = 0; i < n; ++i) {
int value = symbolValues[s[i]];
if (i < n - 1 && value < symbolValues[s[i + 1]]) {
ans -= value;
} else {
ans += value;
}
}
return ans;
}
};
4.最长公共前缀
题目
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""。
示例 1:
输入:strs = ["flower","flow","flight"] 输出:"fl"
示例 2:
输入:strs = ["dog","racecar","car"] 输出:"" 解释:输入不存在公共前缀。
提示:
-
1 <= strs.length <= 200 -
0 <= strs[i].length <= 200 -
strs[i]如果非空,则仅由小写英文字母组成
思路
方法一:纵向扫描,输入:strs = ["flower","flow","flight"]
即flower
flow
flight
从上到下第一个字母全是 f,第二个字母全是 l,第三列就不全一样了,所以「最长公共前缀」是 fl。
class Solution {
public String longestCommonPrefix(String[] strs) {
int min=strs[0].length();
for(int k=0;k<strs.length;k++){
if(strs[k].length()<min)
min=strs[k].length();
}
int flag=0;
StringBuilder s=new StringBuilder();
for(int i=0;i<min;i++){
for (int j=0;j<strs.length;j++){
if(j+1!=strs.length && strs[j].charAt(i)!=strs[j+1].charAt(i)){
flag=1;
break;
}
}
if (flag==1) break;
else s.append(strs[0].charAt(i));
}
return s.toString();
}
}
方法二:横向扫描:依次遍历字符串数组中的每个字符串,对于每个遍历到的字符串,更新最长公共前缀,当遍历完所有的字符串以后,即可得到字符串数组中的最长公共前缀。(力扣)
class Solution {
public String longestCommonPrefix(String[] strs) {
if (strs == null || strs.length == 0) {
return "";
}
String prefix = strs[0];
int count = strs.length;
for (int i = 1; i < count; i++) {
prefix = longestCommonPrefix(prefix, strs[i]);
if (prefix.length() == 0) {
break;
}
}
return prefix;
}
public String longestCommonPrefix(String str1, String str2) {
int length = Math.min(str1.length(), str2.length());
int index = 0;
while (index < length && str1.charAt(index) == str2.charAt(index)) {
index++;
}
return str1.substring(0, index);
}
}
有效的括号
题目
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
-
左括号必须用相同类型的右括号闭合。
-
左括号必须以正确的顺序闭合。
-
每个右括号都有一个对应的相同类型的左括号。
示例 1:
输入:s = "()"
输出:true
示例 2:
输入:s = "()[]{}"
输出:true
示例 3:
输入:s = "(]"
输出:false
示例 4:
输入:s = "([])"
输出:true
提示:
-
1 <= s.length <= 104 -
s仅由括号'()[]{}'组成
思路
栈:首先如果字符串长度是奇数,一定为false
遇到左括号时将其放入栈顶,遇到右括号时可以取出站定的括号检查是否左右括号匹配,如果匹配则栈顶出栈,不匹配则说明括号顺序不符合逻辑,返回false
为了快速判断括号的类型,我们可以使用哈希表存储每一种括号。哈希表的键为右括号,值为相同类型的左括号。
最后检查遍历结束后栈中是否没有左括号
//力扣
class Solution {
public boolean isValid(String s) {
int n = s.length();
if (n % 2 == 1) {
return false;
}
Map<Character, Character> pairs = new HashMap<Character, Character>() {{
put(')', '(');
put(']', '[');
put('}', '{');
}};
Deque<Character> stack = new LinkedList<Character>();
for (int i = 0; i < n; i++) {
char ch = s.charAt(i);
if (pairs.containsKey(ch)) {
if (stack.isEmpty() || stack.peek() != pairs.get(ch)) {
return false;
}
stack.pop();
} else {
stack.push(ch);
}
}
return stack.isEmpty();
}
}
6.合并两个有序链表
题目
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = [] 输出:[]
示例 3:
输入:l1 = [], l2 = [0] 输出:[0]
提示:
-
两个链表的节点数目范围是
[0, 50] -
-100 <= Node.val <= 100 -
l1和l2均按 非递减顺序 排列
思路
1.通过迭代的方式,在一次遍历中完成了两个有序单链表的合并,同时扫描两个链表,只要它们都还有节点没处理,就对比当前节点的值。把值小的节点接到新链表后面,当其中一个链表遍历完了,把另一个链表剩下的部分直接接到新链表末尾。
造一个 “假” 的头结点,用另一个指针指向它。这么做是为了避免后续对头结点进行特殊判断,简化操作。新链表的头就是虚拟头结点的下一个节点。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
**/
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if (list1 == null) return list2;
if (list2 == null) return list1;
ListNode dummy = new ListNode();
ListNode list3 = dummy;
while(list1!=null && list2!=null){
if(list1.val<list2.val){
list3.next = list1;
list1 = list1.next;
}else{
list3.next = list2;
list2 = list2.next;
}
list3 = list3.next;
}
if (list1 != null) {
list3.next = list1;
}
if (list2 != null) {
list3.next = list2;
}
return dummy.next;
}
}
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode prehead = new ListNode(-1);
ListNode prev = prehead;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
prev.next = l1;
l1 = l1.next;
} else {
prev.next = l2;
l2 = l2.next;
}
prev = prev.next;
}
// 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
prev.next = l1 == null ? l2 : l1;
return prehead.next;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/merge-two-sorted-lists/solutions/226408/he-bing-liang-ge-you-xu-lian-biao-by-leetcode-solu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2.递归
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) {
return l2;
} else if (l2 == null) {
return l1;
} else if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/merge-two-sorted-lists/solutions/226408/he-bing-liang-ge-you-xu-lian-biao-by-leetcode-solu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
7.删除有序数组中的重复项
题目
给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。
考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:
-
更改数组
nums,使nums的前k个元素包含唯一元素,并按照它们最初在nums中出现的顺序排列。nums的其余元素与nums的大小不重要。 -
返回
k。
判题标准:
系统会用下面的代码来测试你的题解:
int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案
int k = removeDuplicates(nums); // 调用
assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
assert nums[i] == expectedNums[i];
}
如果所有断言都通过,那么您的题解将被 通过。
示例 1:
输入:nums = [1,1,2] 输出:2, nums = [1,2,_] 解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
示例 2:
输入: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 。不需要考虑数组中超出新长度后面的元素。
提示:
-
1 <= nums.length <= 3 * 104 -
-104 <= nums[i] <= 104 -
nums已按 非严格递增 排列
思路
使用哈希表检测数字是否已经出现,遍历一定大于等于赋值,如果没有出现, 则从头开始更新数组,并使长度加一
class Solution {
public int removeDuplicates(int[] nums) {
int count=0,j=0;
Map<Integer,Integer> map=new HashMap<>();
for(int i = 0; i<nums.length; i++){
if(map.containsKey(nums[i])) continue;
else {
map.put(nums[i],i);
nums[j]=nums[i];
j++;
count++;
}
}
return count;
}
}
双指针:由于数组是非严格递增排列,相等的元素在数组中的下标一定是连续的,[0,0,1,1,1,1,2,2]那么如果两个相邻的元素不相等,说明来新元素了
定义两个指针fast和slow,分别为快指针和慢指针,快指针表示遍历数组到达的下标位置,慢指针表示下一个不同元素要填入的下标位置,对于每个位置,如果 nums[fast]
=nums[fast−1],说明 nums[fast] 和之前的元素都不同,因此将 nums[fast] 的值复制到 nums[slow],然后将 slow 的值加 1,即指向下一个位置。

class Solution {
public int removeDuplicates(int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
}
int fast = 1, slow = 1;
while (fast < n) {
if (nums[fast] != nums[fast - 1]) {
nums[slow] = nums[fast];
++slow;
}
++fast;
}
return slow;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-array/solutions/728105/shan-chu-pai-xu-shu-zu-zhong-de-zhong-fu-tudo/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
8.移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。
假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:
-
更改
nums数组,使nums的前k个元素包含不等于val的元素。nums的其余元素和nums的大小并不重要。 -
返回
k。
用户评测:
评测机将使用以下代码测试您的解决方案:
int[] nums = [...]; // 输入数组
int val = ...; // 要移除的值
int[] expectedNums = [...]; // 长度正确的预期答案。
// 它以不等于 val 的值排序。
int k = removeElement(nums, val); // 调用你的实现
assert k == expectedNums.length;
sort(nums, 0, k); // 排序 nums 的前 k 个元素
for (int i = 0; i < actualLength; i++) {
assert nums[i] == expectedNums[i];
}
如果所有的断言都通过,你的解决方案将会 通过。
示例 1:
输入:nums = [3,2,2,3], val = 3 输出:2, nums = [2,2,_,_] 解释:你的函数函数应该返回 k = 2, 并且 nums 中的前两个元素均为 2。 你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。
示例 2:
输入:nums = [0,1,2,2,3,0,4,2], val = 2 输出:5, nums = [0,1,4,0,3,_,_,_] 解释:你的函数应该返回 k = 5,并且 nums 中的前五个元素为 0,0,1,3,4。 注意这五个元素可以任意顺序返回。 你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。
提示:
-
0 <= nums.length <= 100 -
0 <= nums[i] <= 50 -
0 <= val <= 100
思路
需要我们把等于val的元素移到数组后面,把不等于val的元素移动到数组前面,不考虑顺序
定义两个指针left,right, left指针从左向右遍历,遇到num[left]==val,left停留,同时right指针从右向左遍历遇到nums[right]!=val停留,然后右替换左
public int removeElement(int[] nums, int val) {
int n=nums.length;
int k=0;
int left = 0, right = n-1;
if(nums==null) return left;
while (left<=right){
while(left<=right&&nums[left]!=val)
{
left++;
}
while(left<=right&&nums[right]==val)
{
right--;
}
if (left < right){
nums[left]=nums[right];
left++;
right--;
}
}
return left;
}
}
移除元素=找不等于val的元素
right从左到右遍历,把right遍历到的拿到左边去
class Solution {
public int removeElement(int[] nums, int val) {
int n = nums.length;
int left = 0;
for (int right = 0; right < n; right++) {
if (nums[right] != val) {
nums[left] = nums[right];
left++;
}
}
return left;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/remove-element/solutions/730203/yi-chu-yuan-su-by-leetcode-solution-svxi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
方法三:
跟我的思路差不多,两个指针初始时分别位于数组的首尾,向中间移动遍历该序列。
但是这个不用判断右指针元素是否等于val,如果左指针还是等于val,右指针继续左移然后赋值
class Solution {
public int removeElement(int[] nums, int val) {
int left = 0;
int right = nums.length;
while (left < right) {
if (nums[left] == val) {
nums[left] = nums[right - 1];
right--;
} else {
left++;
}
}
return left;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/remove-element/solutions/730203/yi-chu-yuan-su-by-leetcode-solution-svxi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
力扣算法学习:基础题解
954

被折叠的 条评论
为什么被折叠?



