03高频题目

7. 整数反转

难度简单2120

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。

示例 1:

输入: 123
输出: 321

示例 2:

输入: -123
输出: -321

示例 3:

输入: 120
输出: 21

注意:

假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。

溢出与否

不管是整数还是负数,都可以通过取每一位依次乘以10相加,如果每一次相加后的结果还原回去不相等的话,说明溢出了,直接返回0,否则返回最终结果。

class Solution {
    public int reverse(int x) {
        int res = 0;
        while( x != 0){
            int tmp = x % 10;
            int ans = res * 10 +tmp;
            if((ans -tmp)/10 != res)
                //溢出了
                return 0;
            res = ans;
            x /= 10;
        }
        return res;
    }
}

148. 排序链表

难度中等700

O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4

示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5

使用优先队列

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
        Queue<ListNode> queue = new PriorityQueue<>((o1,o2)->(o1.val -o2.val));
        while(head != null){
            queue.offer(head);
            head = head.next;
        }
        ListNode node = new ListNode(0);
        ListNode cur = node;
        while(!queue.isEmpty()){
            cur.next = queue.poll();
            cur = cur.next;
        }
        cur.next = null;
        return node.next;
    }
}

归并排序解决

class Solution {
    public ListNode sortList(ListNode head) {
        //非递归归并排序
        int len = 0;
        for(ListNode x = head;x!=null;x=x.next){
            len++;
        }
        ListNode vNode = new ListNode(0);
        vNode.next = head;//增加虚拟节点
        for(int i= 1; i < len ;i=i*2){
            ListNode vir = vNode;//使用虚拟节点
            for(int j = 0; j + i < len; j = j + 2 * i){//这里如果剩余元素小于i说明不用排序了
                ListNode first = vir.next,second = first;//归并排序得两个起点
                for(int k=0;k<i;k++) 
                    second = second.next;
                int f=0,s=0;
                //两个归并序列移动得次数
                while(f<i && s<i && second != null){
                    if(first.val < second.val){
                        vir.next = first;
                        vir = vir.next;
                        first = first.next;
                        f++;
                    }else{
                        vir.next = second;
                        vir = vir.next;
                        second = second.next;
                        s++;
                    }
                }
                //未排完
                while(f < i){
                        vir.next = first;
                        vir = vir.next;
                        first = first.next;
                        f++;
                }
                while(s < i && second!=null){
                        vir.next = second;
                        vir = vir.next;
                        second = second.next;
                        s++;
                }
                //新的虚拟节点开始
                vir.next = second;//注意此处为当前是虚拟节点,由于second已经到达后面得起始点
            }
        }
        return vNode.next;
    }
}

78. 子集

难度中等716

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

**说明:**解集不能包含重复的子集。

示例:

输入: nums = [1,2,3]
输出:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]
class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        //使用二进制模拟需要和不需要取得数字
         List<List<Integer>> list = new ArrayList<>();
        for(int i=0;i<(1 << nums.length);i++){
            //一共模拟000...000 - 111...111得情况,符合全排列得关系
            List<Integer> sub = new ArrayList<>();
            //根据此时每位得结果
            for(int j=0;j<nums.length;j++){
                //第j位判断是否需要加入
                if(((i >> j) & 1) == 1)
                    sub.add(nums[j]);//第j位为1,说明需要添加
            }
            list.add(sub);
        }
        return list;
    }
}

46. 全排列

难度中等852

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

使用回溯

添加一个数组判断是否使用过,记录已有长度以及总长度,相等添加(需要转化为新的列表添加),

没有得话添加没添加过得,递归添加,添加后重置当前位置得状态(状态以及路径)。

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        //回溯法解决
        List<List<Integer>> res = new ArrayList<>();
        int len = nums.length;//长度
        if(len == 0) return res;
        boolean[] isUsed = new boolean[len];//标记数字是否使用过
        List<Integer> path = new ArrayList<>();//走过的路径
        dfs(nums,len,0,path,isUsed,res);//数组、总长、当前路径长度、路径、标记、结果
        return res;
     }
    public void dfs(int[] nums,int len,int depth,List<Integer> path,boolean[] isUsed, List<List<Integer>> res){
        if(depth == len){
            res.add(new ArrayList<>(path)); //添加后重新new一个 不能改变path
            return;
        }//已经遍历完毕
        
        for(int i=0;i<len;i++){
            if(!isUsed[i]){
                //当前数字未被使用
                path.add(nums[i]);
                isUsed[i] = true;
                dfs(nums,len,depth+1,path,isUsed,res);
                //搜索后取消此状态
                isUsed[i] = false;
                path.remove(path.size()-1);
            }
        }
    }
}

94. 二叉树的中序遍历

难度中等637

给定一个二叉树,返回它的中序 遍历。

示例:

输入: [1,null,2,3]
   1
    \
     2
    /
   3

输出: [1,3,2]

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

栈辅助处理

需要先操作左边节点,然后中间,最后右边,因此每次先把所有左节点放入,然后每次取栈顶后再访问右边。

直到栈空且右边也无节点了。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        //中序:左中右
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        //有左子树就放进去,没有得话就弹出
        TreeNode cur = root;//用于标记当前打印的节点
        while(cur!=null || !stack.isEmpty()){//说明还有数据未操作
            while(cur!=null){//左子树未遍历完成
                //先打印左边得节点
                stack.push(cur);
                cur = cur.left;
            }
            //先打印栈顶也就是本身,然后打印右子树
            cur = stack.pop();
            res.add(cur.val);
            cur = cur.right;
        }
        return res;
    }
}

70. 爬楼梯

难度简单1197

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

**注意:**给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶
class Solution {
    public int climbStairs(int n) {
        //0 1 2 3 4
        //  1 2 3 5
        if(n == 0) return 1;
        if(n <= 3) return n;
        int dp0 = 2;
        int dp2 = 3;
        for(int i=4;i<=n;i++){
            int tmp = dp0+dp2;
            dp0 = dp2;
            dp2 =tmp;
        }
        return dp2;
    }
}

剑指 Offer 59 - I. 滑动窗口的最大值

难度简单89

给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。

示例:

输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7] 
解释: 

  滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

暴力解决

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length == 0) return new int[0];
        
        int[] ans = new int[nums.length - k +1];
        for(int i=-1;i<nums.length-k;i++){
            int v = nums[i+1];//左边
            for(int j=2;j<=k;j++) v = Math.max(v,nums[i+j]);
            ans[i+1] = v;
        }
        return ans;
    }
}

存储最大索引

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length == 0) return new int[0];
        int maxIndex = -1;
        int[] ans = new int[nums.length - k +1];
        for(int i=-1;i<nums.length-k;i++){
            if(maxIndex >= i+1)
                maxIndex = nums[i+k] > nums[maxIndex] ? i+k : maxIndex;
            else{
                maxIndex = i+1;
                for(int j=2;j<=k;j++){
                    maxIndex = nums[i+j] > nums[maxIndex] ? i+j : maxIndex;
                }
            }
            ans[i+1] = nums[maxIndex];
        }
        return ans;
    }
}

面试题 02.08. 环路检测

难度中等28

给定一个链表,如果它是有环链表,实现一个算法返回环路的开头节点。
有环链表的定义:在链表中某个节点的next元素指向在它前面出现过的节点,则表明该链表存在环路。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。

进阶:
你是否可以不用额外空间解决此题?

快慢指针

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head == null || head.next == null) return null;
        ListNode low = head;
        ListNode quick = head;//一次走两格
        while(low != null && quick!=null){
            low = low.next;
            if(quick.next ==null){
                quick = quick.next;//需要判断是否可以走两格
                break;
            }
            quick = quick.next.next;
            if(quick == low) break;
        }
        if(quick == null || low == null) return null;//不存在环
        low = head;//从头追赶
        while(low != quick){ 
            low = low.next;
            quick = quick.next;
        }
        return low;
    }
}

//一次走两格
while(low != null && quick!=null){
low = low.next;
if(quick.next ==null){
quick = quick.next;//需要判断是否可以走两格
break;
}
quick = quick.next.next;
if(quick == low) break;
}
if(quick == null || low == null) return null;//不存在环
low = head;//从头追赶
while(low != quick){
low = low.next;
quick = quick.next;
}
return low;
}
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值