977. 有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
提示:
1 <= nums.length <= 10^4
-10^4 <= nums[i] <= 10 ^4
nums 已按 非递减顺序 排序
示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
示例 2:
输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]
解析过程:
最简单的方法,就是直接开辟一个新的数组,然后将每个数字进行平方,并存储在新数组中,再对新数组进行排序即可。
class Solution {
public int[] sortedSquares(int[] nums) {
int[] nums1=new int[nums.length];
for(int i=0;i<nums.length;i++){
nums1[i]=nums[i]*nums[i];
}
Arrays.sort(nums1);
return nums1;
}
}
结果:
执行用时:2 ms, 在所有 Java 提交中击败了42.42%的用户
内存消耗:40.2 MB, 在所有 Java 提交中击败了58.25%的用户
通过测试用例:137 / 137
189. 旋转数组
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
提示:
1 <= nums.length <= 2 * 10^4
-2^31 <= nums[i] <= 2 ^31 - 1
0 <= k <= 10^5
进阶:
尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗?
示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右旋转 1 步: [7,1,2,3,4,5,6]
向右旋转 2 步: [6,7,1,2,3,4,5]
向右旋转 3 步: [5,6,7,1,2,3,4]
示例 2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释:
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]
解析过程:
开辟一个新的数组,遍历原数组,将原数组中下标为i的元素重新放到下标为(i+k)%nums.length的位置,之后将新数组拷贝到原数组即得所求。
class Solution {
public void rotate(int[] nums, int k) {
int[] nums1=new int[nums.length];
for(int i=0;i<nums.length;i++){
nums1[(i+k)%nums.length]=nums[i];
}
System.arraycopy(nums1,0,nums,0,nums.length);
}
}
结果:
执行用时:1 ms, 在所有 Java 提交中击败了61.71%的用户
内存消耗:55.3 MB, 在所有 Java 提交中击败了44.98%的用户
通过测试用例:38 / 38
283. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。
解析过程:
采用快慢指针的思想
class Solution {
public void moveZeroes(int[] nums) {
if (nums == null || nums.length== 0) {
return;
}
int temp=0;
int slow=0;
for(int fast=0;fast<nums.length;fast++){
if(nums[fast]!=0){
if(fast!=slow){
temp=nums[fast];
nums[fast]=nums[slow];
nums[slow]=temp;
}
slow++;
}
}
}
}
结果:
74 / 74 个通过测试用例
状态:通过
执行用时: 2 ms
内存消耗: 39.8 MB
167. 两数之和 II - 输入有序数组
给定一个已按照 非递减顺序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
示例 1:
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
示例 2:
输入:numbers = [2,3,4], target = 6
输出:[1,3]
示例 3:
输入:numbers = [-1,0], target = -1
输出:[1,2]
过程解析:
采用双指针的技巧,该题解法类似于二分搜索,通过sum的大小来调节left和right的移动。与之前两数之和的区别在于,该题是有序数组!!!
class Solution {
public int[] twoSum(int[] numbers, int target) {
int left=0,right=numbers.length-1;
while(left<right){
int sum=numbers[left]+numbers[right];
if(sum==target){
return new int[] {left+1,right+1};
}else if(sum<target){
left++;
}else if(sum>target){
right--;
}
}
return new int[] {-1,-1};
}
}
结果:
执行用时:1 ms, 在所有 Java 提交中击败了66.14%的用户
内存消耗:38.5 MB, 在所有 Java 提交中击败了75.60%的用户
通过测试用例:19 / 19
344. 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
示例 1:
输入:s = [“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]
示例 2:
输入:s = [“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]
过程解析:
采用双指针的思想
class Solution {
public void reverseString(char[] s) {
if(s==null||s.length==0){
return;
}
int left=0,right=s.length-1;
while(left<right){
char temp=' ';
temp=s[left];
s[left]=s[right];
s[right]=temp;
left++;
right--;
}
}
}
结果:
执行用时:1 ms, 在所有 Java 提交中击败了95.62%的用户
内存消耗:44.7 MB, 在所有 Java 提交中击败了89.28%的用户
通过测试用例:477 / 477
557. 反转字符串中的单词 III
给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。
示例:
输入:“Let’s take LeetCode contest”
输出:“s’teL ekat edoCteeL tsetnoc”
过程解析:
class Solution {
public String reverseWords(String s) {
//先将字符串转为字符串数组
char[] arr=s.toCharArray();
//新建一个数组,用来存放逆序的单词
char[] word=new char[arr.length];
int i=0,j=0;
int k=0;// 下一次往新数组中存储单词时的起始位置(k是在数组arr中)
while(i<arr.length){
//判断数组中当前字符是否为空字符,若是,则将前面的一个单词反转存储在数组中
if(arr[i]==' '){
for(int t=i-1;t>=k;t--){
//将单词逆序存放
word[j++]=arr[t];
}
word[j]=' '; //在添加的逆序单词后面加一个空字符
j++;
k=i+1;
}
i++;
}
//由于最后一个单词后面没有空字符,所以拿出来单独存储
for(int t=i-1;t>=k;t--){
word[j++]=arr[t];
}
//将数组再转为字符串
String str=String.valueOf(word);
return str;
}
}
结果:
执行用时:2 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38.4 MB, 在所有 Java 提交中击败了98.78%的用户
通过测试用例:29 / 29
876. 链表的中间结点
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
提示:给定链表的结点数介于 1 和 100 之间。
示例 1:
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 2:
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。
过程解析:
方法一:
/**
* 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 middleNode(ListNode head) {
//双指针的思想(快慢指针)
ListNode fast=head,slow=head;
//慢指针前进一步,快指针前进两步,当fast走到链表最后一个节点时,slow所指位置即为链表的中间节点
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
}
return slow;
}
}
结果:
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:35.9 MB, 在所有 Java 提交中击败了30.14%的用户
通过测试用例:36 / 36
方法二:
/**
* 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 middleNode(ListNode head) {
//数组思想
ListNode[] array=new ListNode[100];
int index=0;
while(head!=null){
array[index++]=head;
head=head.next;
}
return array[index/2];
}
}
结果:
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:36 MB,在所有 Java 提交中击败了15.84%的用户
通过测试用例:36 / 36
19. 删除链表的倒数第 N 个结点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
示例 1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1
输出:[]
示例 3:
输入:head = [1,2], n = 1
输出:[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 removeNthFromEnd(ListNode head, int n) {
//快慢指针思想
//快指针先前进n步,之后快慢指针同时前进,当快指针走到最后一个节点时,满指针所指位置即为倒数第n个节点
//初始化一个空节点,初始赋值为0,并且list的下一个next指针指向head,指针指向为zero
ListNode zero=new ListNode(0,head);
ListNode fast=head,slow=zero;
while(n>0){
fast=fast.next;
n--;
}
while(fast!=null){
fast=fast.next;
slow=slow.next;
}
slow.next=slow.next.next; //将倒数第n个节点删除
ListNode node=zero.next;
return node;
}
}
结果:
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:36.3 MB, 在所有 Java 提交中击败了74.18%的用户
通过测试用例:208 / 208
141. 环形链表
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
进阶:你能用 O(1)(即,常量)内存解决此问题吗?
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
解析过程:
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
//快慢指针思想,如果链表中没有环,则跑的快的那个指针会返回null;如果链表中含有环,则快指针超慢指针1圈,和慢指针相遇
ListNode fast,slow;
fast=slow=head;
while(fast !=null && fast.next!=null){
//快指针每次前进两步,慢指针前进一步
fast=fast.next.next;
slow=slow.next;
if(fast==slow){
return true;
}
}
return false;
}
}
结果:
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:39.7 MB, 在所有 Java 提交中击败了14.83%的用户
通过测试用例:20 / 20
21. 合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
提示:
两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = []
输出:[]
示例 3:
输入:l1 = [], l2 = [0]
输出:[0]
解析过程:
/**
* 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 l1, ListNode l2) {
//暴力解法,逐一比较取最小值
//引入一个哑结点,值为-1
ListNode prehead=new ListNode(-1);
ListNode pre=prehead;
while(l1!=null&&l2!=null){
if(l1.val<l2.val){
pre.next=l1;
l1=l1.next;
}else {
pre.next=l2;
l2=l2.next;
}
pre=pre.next;
}
//合并完后会有其中一个链表未合并完,则直接将链表的末尾指向未合并完的链表即可
pre.next=l1==null ?l2:l1;
return prehead.next;
}
}
调试:
public class Main {
public static void main(String[] args) {
ListNode node1= new ListNode(1);
ListNode node2= new ListNode(1);
ListNode node3= new ListNode(2);
ListNode node4= new ListNode(3);
ListNode node5= new ListNode(4);
ListNode node6= new ListNode(4);
node1.next=node3;
node3.next=node5;
node2.next=node4;
node4.next=node6;
ListNode pr= new Leetcode21().mergeTwoLists(node1,node2);
while(pr !=null){
System.out.print(pr.val +" ");
pr=pr.next;
}
}
}
结果:
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38 MB, 在所有 Java 提交中击败了5.13%的用户
通过测试用例:208 / 208
203. 移除链表元素
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
示例 2:
输入:head = [], val = 1
输出:[]
示例 3:
输入:head = [7,7,7,7], val = 7
输出:[]
解析过程:
/**
* 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 removeElements(ListNode head, int val) {
//暴力解法,依次遍历,如果节点的值等于val,就删除
//设置一个哑结点,值为-1
ListNode prehead=new ListNode(-1);
prehead.next=head;
ListNode pre=prehead;
while(pre.next !=null){
//如果pre 的下一个节点不为空且下一个节点的节点值等于val,则需要删除下一个节点
if( pre.next.val == val){
pre.next=pre.next.next;
}else {
pre=pre.next;
}
}
return prehead.next;
}
}
调试:
public class Main {
public static void main(String[] args) {
ListNode node1= new ListNode(1);
ListNode node2= new ListNode(2);
ListNode node3= new ListNode(6);
ListNode node4= new ListNode(3);
ListNode node5= new ListNode(4);
ListNode node6= new ListNode(5);
ListNode node7= new ListNode(6);
node1.next=node2;
node2.next=node3;
node3.next=node4;
node4.next=node5;
node5.next=node6;
node6.next=node7;
int val=6;
ListNode pr= new Leetcode203().removeElements(node1,val);
ListNode ps= new PrintListNode().printListNode(pr);
}
public class PrintListNode {
public ListNode printListNode(ListNode l1){
while(l1 !=null){
System.out.print(l1.val +" ");
l1=l1.next;
}
return l1;
}
}
结果:
执行用时:1 ms, 在所有 Java 提交中击败了96.26%的用户
内存消耗:39.1 MB, 在所有 Java 提交中击败了87.49%的用户
通过测试用例:66 / 66
206. 反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
提示:
链表中节点的数目范围是 [0, 5000]
-5000 <= Node.val <= 5000
示例 1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2]
输出:[2,1]
示例 3:
输入:head = []
输出:[]
解析过程:
方法一:递归
/**
* 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 reverseList(ListNode head) {
if(head==null||head.next==null){
return head;
}
ListNode rehead=reverseList(head.next);
head.next.next=head;
//注意,head的下一个节点一定要指向空
head.next=null;
return rehead;
}
}
结果:
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38.1 MB, 在所有 Java 提交中击败了68.66%的用户
通过测试用例:28 / 28
/**
* 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 reverseList(ListNode head) {
//方法二:迭代
if(head==null||head.next==null){
return head;
}
ListNode pre=null;
ListNode rehead=head;
while(rehead != null){
//设置一个节点来存储后一个节点
ListNode node=rehead.next;
//让当前节点的指针指向上一个节点
rehead.next=pre;
pre=rehead;
rehead=node;
}
return pre;
}
}
结果:
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38.2 MB, 在所有 Java 提交中击败了48.00%的用户
通过测试用例:28 / 28
83. 删除排序链表中的重复元素
存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除所有重复的元素,使每个元素 只出现一次 。
返回同样按升序排列的结果链表。
提示:
链表中节点数目在范围 [0, 300] 内
-100 <= Node.val <= 100
题目数据保证链表已经按升序排列
示例 1:
输入:head = [1,1,2]
输出:[1,2]
示例 2:
输入:head = [1,1,2,3,3]
输出:[1,2,3]
解析过程:
/**
* 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 deleteDuplicates(ListNode head) {
if(head==null||head.next==null){
return head;
}
ListNode p=head; //当前节点
while(p!=null&&p.next!=null){
if(p.val==p.next.val){
p.next=p.next.next;
}else{
p=p.next;
}
}
return head;
}
}
结果:
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:37.8 MB, 在所有 Java 提交中击败了77.02%的用户
通过测试用例:166 / 166
237. 删除链表中的节点
请编写一个函数,用于 删除单链表中某个特定节点 。在设计函数时需要注意,你无法访问链表的头节点 head ,只能直接访问 要被删除的节点 。
题目数据保证需要删除的节点 不是末尾节点 。
提示:
链表中节点的数目范围是 [2, 1000]
-1000 <= Node.val <= 1000
链表中每个节点的值都是唯一的
需要删除的节点 node 是 链表中的一个有效节点 ,且 不是末尾节点
示例 1:
输入:head = [4,5,1,9], node = 5
输出:[4,1,9]
解释:指定链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9
示例 2:
输入:head = [4,5,1,9], node = 1
输出:[4,5,9]
解释:指定链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9
示例 3:
输入:head = [1,2,3,4], node = 3
输出:[1,2,4]
示例 4:
输入:head = [0,1], node = 0
输出:[1]
示例 5:
输入:head = [-3,5,-99], node = -3
输出:[5,-99]
解析过程:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public void deleteNode(ListNode node) {
//题目已保证需要删除的节点不是末尾节点
//将要删除的节点值与下一个节点的进行交换,然后删除下一个节点
node.val=node.next.val;
node.next=node.next.next;
}
}
结果:
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:37.8 MB, 在所有 Java 提交中击败了68.12%的用户
通过测试用例:41 / 41