欢迎来到我的小小世界

Change is a million times less painful than regret

0%

题目地址(7. 整数反转)

https://leetcode-cn.com/problems/reverse-integer/

题目描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231,  231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

 

示例 1:

输入:x = 123
输出:321


示例 2:

输入:x = -123
输出:-321


示例 3:

输入:x = 120
输出:21


示例 4:

输入:x = 0
输出:0


 

提示:

-231 <= x <= 231 - 1

前置知识

公司

  • 字节跳动、百度

思路

题目解答主要有两种思路,一种是使用字符串的翻转,但是这样不符合题目原意;另一种则是进行数学计算,同时要注意的是,在进行数学计算的时候,由于题目要求不使用64位进行存储,所以使用long数据类型也是不合题意的,这里就要涉及到关于int类型边界的判断了。判断时需要注意的点有以下几点:

阅读全文 »

题目地址(9. 回文数)

https://leetcode-cn.com/problems/palindrome-number/

题目描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。

 

示例 1:

输入:x = 121
输出:true


示例 2:

输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。


示例 3:

输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。


示例 4:

输入:x = -101
输出:false


 

提示:

-231 <= x <= 231 - 1

 

进阶:你能不将整数转为字符串来解决这个问题吗?

前置知识

  • 字符串转换(最基础的想法)

公司

  • amazon Apple

思路1

此题如果采用最基础的解法就是将给定数字转化为字符串,然后使用str.charAt(i)函数首位对比,然后进行判断

阅读全文 »

题目地址(3sum/“>15. 三数之和)

https://leetcode-cn.com/problems/3sum/

题目描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

 

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]


示例 2:

输入:nums = []
输出:[]


示例 3:

输入:nums = [0]
输出:[]


 

提示:

0 <= nums.length <= 3000
-105 <= nums[i] <= 105

前置知识

  • 双指针、两数之和

公司

  • 字节跳动、Facebook、微软、苹果

思路

这题的思路是建立在两数之和的基础进行求解的,与两数之和不同的是,这里不再要求返回索引,,因此先进行排序,,然后使用双指针的思路是颗星的。具体的算法是对原数组进行依次排序,然后一层循环固定一个元素,循环内部利用双指针找出剩下的两个元素,这里特别注意需要去重。上述算法出去排序部分的时间复杂度为O(n^2),相比之下排序过程不会成为性能瓶颈。

阅读全文 »

题目地址(1. 两数之和)

https://leetcode-cn.com/problems/two-sum/

题目描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
给定一个整数数组 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
只会存在一个有效答案

进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?

前置知识

  • 哈希表的元素存在判断,哈希表的存储和读出

公司

  • Amazon、字节跳动、谷歌、微软、苹果

思路

此题作为LeetCode的第一题,最容易想到的就是使用暴力的方法进行枚举,O(N^2)的复杂度就可以将最终结果解出来,但是这样的效率是非常低的,显然不是题目本身的意图。这里可以使用哈希表的解法,每次将nums中元素添加到哈希表中时,使用containsKey()进行判断,判断是否有相加为target的元素已经存在哈希表中,如果存在直接返回对应的下标,如果没有,则将当前元素以num[i]为key,索引为value存入到哈希表中。

阅读全文 »

题目地址(283. 移动零)

https://leetcode-cn.com/problems/move-zeroes/

题目描述

1
2
3
4
5
6
7
8
9
10
11
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

说明:

必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。

前置知识

  • 双指针

公司

  • Facebook 、字节跳动、微软、苹果等

思路

这个题本身并不难,使用暴力循环比较一定能做出来,而且代码逻辑也不复杂,但是效率非常的低,这里采用另一种思路:使用双指针,即设置一个pre和last两个指针,pre指向首部,last指向尾部。在正式比较前可以使用两个指针缩短一下比较范围,当首部有非零数时,pre指针向右移动,当尾部有零时,last向左移动。正式比较时,最外层循环代表要比较的数,注意这里不要直接i++,这样出现一个问题:当两个连续的零在一起的时候,第一个零正常移动到最后时,i此时停留在1处,然而第二个零已经到了i=0的位置上了,这样就会出现遗漏的情况。进入第二层循环的时候,就是进行换位的操作,这里也有一个比较坑的点,就是j要从i开始,不能从0开始,否则会出现把第0号元素给调换,但实际上根据逻辑,i之前的已经全部是非零数了(只有非零,i才会++),切记j从i开始,然后每一次将零换到最后,last都向前移动一个,下次就不用比较了,直到最后。

阅读全文 »

题目

传送门

解题思路

这题属实让eclipse坑了一把,不说那话。这题我一开始想的复杂了,最开始想用的HashMap进行求解,将最高位按照低到高进行排列,每个最高位内部再进行一次排列,这样最后就直接按顺序将所有的整数以字符串的形式拼接并输出就可以,但是还是太年轻了,如果只考虑最高位的话,会出现多个最高位相同的情况例如:334,35,369等等,这样的话就会导致一个问题,即多个相同值的key(最高位都一样)都会指向唯一一个value,这样最后每一种最高位都只剩下一个数,显然不合要求;第二次考虑使用二维数组进行实现,同样遇到了不可弥补的问题。最后,还是采用了题解中的一种做法,就是相邻两个数进行正反拼接,若nums[j]+nums[j+1]>nums[j+1]+nums[j],注意这里的加法是字符串的加法,不是数字相加,nums[j]应移动到j+1的后面去,这里的排序就是用冒泡(毕竟要求用冒泡),排序完成后再按照顺序进行字符串拼接,最后进行输出。其实这里涉及到一个问题,也就是排序规则的传递性问题,意思是,每次比较都是相邻两个数拼接之后比较,排序完成后怎样保证字符串 满足xy < yx , yz < zy 时 xz < zx 一定成立。后面给出K神关于传递性的证明。

传递性证明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
设十进制数 x, y, z 分别有 a, b, c 位,则有:
(左边是字符串拼接,右边是十进制数计算,两者等价)
xy = x * 10^b + y
yx = y * 10^a + x

则 xy < yx 可转化为:
x * 10^b + y < y * 10^a + x
x (10^b - 1) < y (10^a - 1)
x / (10^a - 1) < y / (10^b - 1) ①

同理, 可将 yz < zy 转化为:
y / (10^b - 1) < z / (10^c - 1) ②

将 ① ② 合并,整理得:
x / (10^a - 1) < y / (10^b - 1) < z / (10^c - 1)
x / (10^a - 1) < z / (10^c - 1)
x (10^c - 1) < z (10^a - 1)
x * 10^c + z < z * 10^a + x
∴ 可推出 xz < zx ,传递性证毕

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public String minNumber(int[] nums) {
String[] str=new String[nums.length];
for(int i=0;i<nums.length;i++) {
str[i]=nums[i]+"";
}
boolean swapped=true;
for(int i=0;i<str.length-1;i++) {
if(!swapped) {
break;
}
swapped=false;
for(int j=0;j<str.length-1-i;j++) {
if((str[j]+str[j+1]).compareTo(str[j+1]+str[j])>=0) {
String tmp="";
tmp=str[j];
str[j]=str[j+1];
str[j+1]=tmp;
swapped=true;
}
}
}

String res="";
for(String v:str) {
res+=v;
}
return res;
}
}

知识点

比较两个String字符串类型数据大小
阅读全文 »

就是传统的冒泡冒泡排序,注释中写的还是比较清楚的的,可以直接读,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class Solution {
public static void swag(int[] arr,int i,int j) {//交换两个数,使用第三方变量的情况
int tmp;
tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
public static void swag_nonum(int[] arr,int i,int j) {
//交换两个数,不使用第三方变量进行转换,利用加减来进行数值的交换

arr[i]+=arr[j];
arr[j]=arr[i]-arr[j];
arr[i]=arr[i]-arr[j];
}
public static void swag_binary(int[] arr,int i,int j) {
//交换两个数,不使用第三方变量进行转换,利用异或操作的交换

arr[i]^=arr[j];
arr[j]^=arr[i];
arr[i]^=arr[j];

}
public static void BubbleSort(int[] arr) {
boolean swapped=true;// 初始时 swapped 为 true,否则排序过程无法启动
for(int i=0;i<arr.length-1;i++) {//-1是为了防止越界
if(!swapped) break;
// 设置 swapped 为 false,如果发生交换,则将其置为 true
swapped=false;
for(int j=0;j<arr.length-1-i;j++) {//减去i是因为每次都会排好一个,不用每次都遍历到最后一个,最后的一个已经是最大的了
if(arr[j]>arr[j+1]) {//比较相邻的两个数的大小,小心数组越界的情况
// 如果左边的数大于右边的数,则交换,保证右边的数字最大
swag(arr,j,j+1);
swapped=true; // 表示发生了交换
}

}
}

}

public static void main(String[] args) {

int arr[]= {9,8,6,4,1,5,9,36,54,7,0,2,5,-1,78};
BubbleSort(arr);
for (int i : arr) {
System.out.print(i+",");
}

}


}

这里在两个数据交换上用了三种方法,一种是用传统的方法,引入第三方变量作为临时存储的介质;另一种采用加法的性质,现将两数(a,b)之和赋值给a,然后用a减去b字得到a的原值并赋值给b,此时再用a-b获得b原来的值并赋值给a,完成两个数之间的交换;最后一种是评论区大神给的异或计算(注意是异或不是加法)进行交换的方法,为了防止第二种情况大数加减时出现的溢出问题。

每日一图

阅读全文 »

题目描述

思路

这一篇与上一篇的区别是,上一篇使用栈来实现,效率非常的低,击败5%也就,这一篇用的是Java对字符串的种种操作来实现的,思路很简单,就是对字符串进行切片或者取余等等。

代码1

因为String类型属于不可变对象,所以使用StringBuilder进行单个字符的添加,将读取到的单个字符添加到StringBuilder中去,最后直接输出就好。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public String reverseLeftWords(String s, int n) {
StringBuilder res=new StringBuilder();
for(int i=n;i<s.length();i++){
res.append(s.charAt(i));
}
for(int i=0;i<n;i++){
res.append(s.charAt(i));//这里遍历到并被添加的元素在StringBuilder中已经不存在了。
}
return res.toString();//根据返回类型将res强制转换成String类型
}
}

代码2

这一部分比上面的要求更加苛刻,不允许使用StringBuilder方法,只能使用Strin数据类型,此时使用字符串遍历拼接,时间和空间复杂度都是O(N),代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution {
public String reverseLeftWords(String s, int n) {
// StringBuilder res=new StringBuilder();
String res="";
for(int i=n;i<s.length();i++){
res+=s.charAt(i);
}
for(int i=0;i<n;i++){
res+=s.charAt(i);
}
return res;
}
}

可以通过取余操作简化代码,还是比较好用和巧妙的。

阅读全文 »

题目

传送门

解题思路

第一中做法用LinkedList模拟的双栈,效率有点低啊
第二种利用LinkedList的双向性直接头尾添加,一个栈输出。

代码(双栈)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public String reverseLeftWords(String s, int n) {
// Char[] a=new Char[s.length];
// a= s.toCharAt();
// StringBuilder str=new StringBuilder(s);
LinkedList<Character> stack1=new LinkedList<>();
LinkedList<Character> stack2=new LinkedList<>();
for (int i =0;i<s.length();i++){
if(n>0){
stack2.addLast(s.charAt(i));
n--;
}
else
stack1.addLast(s.charAt(i));
}
String str="";
while(!stack1.isEmpty()){
str+=stack1.removeFirst();
}
while(!stack2.isEmpty()){
str+=stack2.removeFirst();
}

return str;
}
}

代码(单栈)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public String reverseLeftWords(String s, int n) {
if(s.length()==1) return s;
LinkedList<Character> stack1=new LinkedList<>();
for (int i =n;i<s.length();i++){
stack1.addFirst(s.charAt(i));
}
String str="";
for(int i=0;i<n;i++){
stack1.addFirst(s.charAt(i));
}
while(!stack1.isEmpty()){
str+=stack1.removeLast();
}

return str;
}
}
阅读全文 »

题目要求

传送门

解题思路

不得不说,大佬的代码对我这种小白来说就是一种恩赐啊。用的是哈希表进行操作的。
利用哈希表的查询特点,考虑构建 原链表节点 和 新链表对应节点 的键值对映射关系,再遍历构建新链表各节点的 next 和 random 引用指向即可。

算法流程:
若头节点head为空节点,直接返回 null
初始化: 哈希表 dic , 节点 cur 指向头节点;
复制链表:
建立新节点,并向 dic 添加键值对 (原 cur 节点, 新 cur 节点) ;
cur 遍历至原链表下一节点;
构建新链表的引用指向:
构建新节点的 next 和 random 引用指向;
cur 遍历至原链表下一节点;
返回值: 新链表的头节点 dic[cur] ;
复杂度分析:
时间复杂度 O(N)O(N) : 两轮遍历链表,使用 O(N)O(N) 时间。
空间复杂度 O(N)O(N) : 哈希表 dic 使用线性大小的额外空间。
  其实就是先复制一个普通的链表出来,然后通过map的方式找到next与random的位置,然后依次赋值给新节点的相应指针指向,最有意思的就是next和random复制的地方,要好好琢磨,有味道。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public Node copyRandomList(Node head) {
if(head == null) return null;//头结点为空直接返回,防止出现空指针异常
Node cur=new Node(head.val);
cur=head;
Map<Node,Node> map=new HashMap<>();
// Map<Node, Node> map = new HashMap<>();
while(cur!=null){
map.put(cur, new Node(cur.val));
cur=cur.next;
}//这里完成的是普通的复制。
cur=head;//这里将cur推回到的开头,准备完成next和random的连接。
while(cur!=null){
map.get(cur).next=map.get(cur.next);
map.get(cur).random=map.get(cur.random);
cur=cur.next;
}
return map.get(head);//因为是旧节点映射新节点,所以直接使用map通过head(一直没动)找到新节点的起始位置,然后直接返回就可以。

}
}

阅读全文 »