目录
4.24
剑指 Offer 03. 数组中重复的数字
题目
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
解1:哈希表
import java.util.HashSet;
class Solution {
public int findRepeatNumber(int[] nums) {
Set<Integer> dic = new HashSet<>();
for(int num : nums) {
if(dic.contains(num)) return num;
dic.add(num);
}
return -1;
}
}
解2:原地交换
注意到,题目说明尚未被充分使用,即 在一个长度为 n 的数组 nums 里的所有数字都在 0 ~ n-1 的范围内 。
此说明含义:数组元素的 索引 和 值 是 一对多 的关系。 因此,可遍历数组并通过交换操作,使元素的 索引 与 值
一一对应(即 nums[i] = inums[i]=i )。因而,就能通过索引映射对应的值,起到与字典等价的作用作者:jyd
链接:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/solution/mian-shi-ti-03-shu-zu-zhong-zhong-fu-de-shu-zi-yua/
class Solution {
public int findRepeatNumber(int[] nums) {
for(int i = 0;i<=nums.length;i++){
if(nums[i] == i){
continue;
}
if(nums[nums[i]]==nums[i]){
return nums[i];
}
else{
int tmp = nums[nums[i]];
nums[nums[i]] = nums[i];
nums[i] = tmp;
}
}
return -1;
}
}
4.23
啊漫长痛苦的期中周总算结束了,我应该有时间睡觉也有时间刷题了XD(虽然刷题也好痛苦…),接下来要备战期末了,但我开始得早就总有时间富余吧…希望接下来一个月能刷够100题……消失期间也在笔面试上做了几道题,回头整理下(靠笔面试刷题也是没谁了)~
LeetCode7. 整数反转
题目
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)
示例 1:
输入:x = 123
输出:321
示例 2:
输入:x = -123
输出:-321
解:取模
class Solution {
public int reverse(int x) {
int rst = 0;
while(x != 0){
int tmp = x % 10;
if(rst > Integer.MAX_VALUE/10 || rst< Integer.MIN_VALUE/10){
return 0;
}
rst = rst * 10 + tmp;
x/=10;
}
return rst;
}
}
comment
哇我竟然一开始就想出最佳解法了可喜可贺!只是不知道怎么判断0的条件然后看了看题解。
//针对本题的精简判断:
if ((ans * 10) / 10 != ans) {
ans = 0;
break;
}
//针对类似题型的通用判断:
if(rev > Integer.MAX_VALUE / 10 || (rev == Integer.MAX_VALUE / 10 && pop > Integer.MAX_VALUE % 10)){
return 0;
}else if(rev < Integer.MIN_VALUE / 10 || (rev == Integer.MIN_VALUE / 10 && x < Integer.MIN_VALUE % 10)){
return 0;
4.5
LeetCode69. x 的平方根
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
解1 exp ln 拆解O(1)
官方题解
class Solution {
public:
int mySqrt(int x) {
if (x == 0) {
return 0;
}
int ans = exp(0.5 * log(x));
return ((long long)(ans + 1) * (ans + 1) <= x ? ans + 1 : ans);
}
};
解2 二分法 O(logx)
题解区思路:
class Solution {
public int mySqrt(int x) {
// 特殊值判断
if(x==0){
return 0 ;
}
if(x==1){
return 1;
}
int left = 1, right = x/2;
while(left<right){//退出时left == right 返回任一即可
int mid = left + (right - left + 1)/2; //+1是防止mid向下取整丢失
//防止乘法整型溢出
if(mid > x/mid){
// [left..mid - 1] 只要mid^2>x,结果一定比mid小
right = mid - 1;
}
else{
// [mid..right]
left = mid;
}
}
return left;
}
}
comment
二分查找的典型应用场景:查找一个有确定范围的整数,根据 单调性 逐渐缩小搜索范围。
注意left right mid边界、特殊情况讨论、避免溢出。
3变形 精确到几位小数 待更新
听说很多面试会考这道题的改版。贴个题解区代码。
public class Solution {
private static double epsilon = 1e-15;
public static void main(String[] args)throws IOException{
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String numStr = bf.readLine().trim();
int x = Integer.parseInt(numStr);
double ans = mySqrt(x,epsilon);
System.out.printf(String.format("%.3f",ans));
}
public static double mySqrt(double x , double epsilon){
double left = 0 , right = x;
if(x == 0 || x == 1){
return x;
}
while(left < right){
double mid = left + (right - left) / 2;
if(Math.abs(mid * mid - x) < epsilon){//重点在这,确保mid^2和目标的差值小于精确度
return mid;
}else if(mid * mid < x){
left = mid;
}else{
right = mid;
}
}
return left;
}
}
作者:xrui-m
链接:https://leetcode-cn.com/problems/sqrtx/solution/java-er-fen-fa-qiu-fu-dian-shu-de-ping-f-k9s5/
来源:力扣(LeetCode)
4.3
206. 反转链表
反转一个单链表。示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
普通循环
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre=null, curr=head, tmp;//分别为第一二个节点
while(curr!=null){
tmp=curr.next;//保存第三个节点
curr.next=pre;//反转一二节点
pre=curr;//分别向前移动
curr=tmp;
}
return pre;//注意提交的是pre,curr已经为null
}
}
递归版
class Solution {
//递归版 仅把原循环改为递归
//注意要把定义从函数中拿出来(整个函数会循环执行)
ListNode pre=null,tmp;//分别为第一二个节点
public ListNode reverseList(ListNode head) {
//head即为原来的curr
//原循环终止条件即为递归出口
if(head==null){
return pre;
}
//以下内容不变
tmp=head.next;//保存第三个节点
head.next=pre;//反转一二节点
pre=head;//分别向前移动
head=tmp;
return reverseList(head);
}
}
还有一种递归版但是自己很难想到,贴题解区解法,原链接的幻灯片逐步演示非常形象。
class Solution {
public ListNode reverseList(ListNode head) {
//递归终止条件是当前为空,或者下一个节点为空
if(head==null || head.next==null) {
return head;
}
//这里的cur就是最后一个节点
ListNode cur = reverseList(head.next);
//这里请配合动画演示理解
//如果链表是 1->2->3->4->5,那么此时的cur就是5
//而head是4,head的下一个是5,下下一个是空
//所以head.next.next 就是5->4
head.next.next = head;
//防止链表循环,需要将head.next设置为空
head.next = null;
//每层递归函数都返回cur,也就是最后一个节点
return cur;
}
}
作者:wang_ni_ma
链接:https://leetcode-cn.com/problems/reverse-linked-list/solution/dong-hua-yan-shi-206-fan-zhuan-lian-biao-by-user74/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
4.1
拖延晚期患者的行动自救,开始刷算法题
LeetCode53. 最大子序和
题目
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 5:
输入:nums = [-100000]
输出:-100000
解1 暴力求解
O(n^2),可略过
class Solution {
public int maxSubArray(int[] nums) {
int sum = -100000 ,tmp = -100000;
for(int i = 0; i < nums.length; i++){
tmp=nums[i];
if(tmp>sum){
sum=tmp;
}
for(int j = i+1; j<nums.length; j++){
tmp += nums[j];
if(tmp>sum){
sum=tmp;
}
}
}
return sum;
}
}
解2 O(n) 累计思想 (贪心算法)
在所有 Java 提交中击败了100% 的用户,内存消耗:38.4 MB。
来自评论区思路。
- 从头开始遍历计算数组的和,一旦和小于0便抛弃。从下一个位置开始计数,重新计算和。
- 有个麻烦是要是全部为负数这个计算规则就失效了,于是记录下这个数组中的最大值,遍历完后如果最大值为负数,则证明整个数组都是负数,把return最大值就行
class Solution {
public int maxSubArray(int[] nums) {
int sum = 0 , tmp = 0, max=nums[0];
for(int i = 0; i < nums.length; i++){
tmp+=nums[i];
if(max<nums[i]){
max=nums[i]; //找数组中最大值max
}
if(tmp>sum){
sum=tmp; //存最大sum值
}
if(tmp<0){
tmp=0;//*关键步骤* 若累加值小于0则抛去,从当前位置开始重新计算
}
}
if(max<0){
sum=max;//若数组全部为负,返回最大的那个负数
}
return sum;
}
}
comment
一开始想不清楚为什么一遍就可以囊括所有情况,后来想到这是一种积分思想,即求积分函数的极值点(这种说法可能不够严谨),那么的确遍历一次即可,只要tmp达到新高度就记录下来。
同时要注意需分为两种情况讨论,一种是数组值全为负,一种是不全为负。在不全为负的情况下,只要能为sum增值便可以收入囊中。
题解区的贪心算法,感觉和上一种差不多,只是代码精简了,但是运行速度稍稍下降。
import java.lang.*;
class Solution {
public int maxSubArray(int[] nums) {
int sum = 0 , ans=nums[0];
for(int num: nums){
if(sum>0){
sum += num;
}
else{//如果sum为负就舍去,从当前值开始
sum = num;
}
ans = Math.max(ans,sum); //也就保证了加入全为时能存下最大值
}
return ans;
}
}