《剑指offer》算法题整理(上):简单题

文章目录

  力扣题库:跳转

〇、刷题建议

  • 先花几天充分学习《数据结构》这门课程,再刷算法题,事半功倍。
  • 按tag刷,这样有利于熟悉API。
  • 同tag下,由简到难刷。
  • 多看看官方解析或评论区优质答案,尤其是不熟练的题目。

一、队、栈

09. 用两个栈实现队列[简单]

  用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

class CQueue {
    
    
    private Stack<Integer> stack1;
    private Stack<Integer> stack2;

    public CQueue() {
    
    
        stack1=new Stack<Integer>();
        stack2=new Stack<Integer>();
    }
    
    public void appendTail(int value) {
    
    
        stack1.push(value);
    }
    
    public int deleteHead() {
    
    
        if(!stack2.empty())return stack2.pop();
        else if(!stack1.empty()){
    
    
            while(!stack1.empty()){
    
    
                stack2.push(stack1.pop());
            }
            return stack2.pop();
        }
        else return -1;
    }
}

/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue obj = new CQueue();
 * obj.appendTail(value);
 * int param_2 = obj.deleteHead();
 */

30. 包含min函数的栈[简单]

  定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数。在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

class MinStack {
    
    
    //stack1存放原本的栈,stack2是辅助栈
    Stack<Integer> stack1,stack2;

    /** initialize your data structure here. */
    public MinStack() {
    
    
        stack1 = new Stack<Integer>();
        stack2 = new Stack<Integer>();
    }
    
    public void push(int x) {
    
    
        stack1.push(x);
        if(stack2.empty()||x<=stack2.peek())stack2.push(x);
    }
    
    //注意,这里用equals方法而不是==,因为元素是Integer类型的而不是int型的
    public void pop() {
    
    
        if(stack1.pop().equals(stack2.peek()))stack2.pop();
    }
    
    public int top() {
    
    
        return stack1.peek();
    }
    
    public int min() {
    
    
        return stack2.peek();
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.min();
 */

59 - I. 滑动窗口的最大值[简单]??

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

class Solution {
    
    
    public int[] maxSlidingWindow(int[] nums, int k) {
    
    
        //如果nums为空或k为0
        if(nums==null||nums.length==0||k==0)return new int[0];
        //deque为辅助双端队列
        Deque<Integer> deque=new ArrayDeque<Integer>();
        int[] max=new int[nums.length-k+1];
        //第一个滑动窗口,得到辅助队列
        for(int i=0;i<k-1;++i){
    
    
            //首先,当前元素得大于等于滑动窗口最右端的元素
            if(nums[i]>=nums[k-1]){
    
    
                //情况一二:队空,或队不空且小于等于队尾元素,直接入队
                if(deque.size()==0||nums[i]<=deque.getLast())deque.addLast(nums[i]);
                //情况三:队不空但大于队尾元素,则让队空,此元素入队
                else {
    
    
                    while(deque.size()!=0)deque.removeFirst();
                    deque.addLast(nums[i]);
                }
            }
        }
        deque.addLast(nums[k-1]);
        max[0]=deque.getFirst();
        System.out.println(max[0]);
        //从第二个滑动窗口开始
        for(int i=1;i<=nums.length-k;++i){
    
    
            //判断队头是否应该出队
            if(nums[i-1]==deque.getFirst())deque.removeFirst();
            //判断窗口中的新元素是否应该入队
            //情况一:队空,或该元素小于等于队尾元素,直接入队
            if(deque.size()==0||nums[k+i-1]<=deque.peekLast())deque.addLast(nums[k+i-1]);
            //情况二:该元素大于队头元素,全部出队,此元素再入队
            else if(nums[k+i-1]>deque.getFirst()){
    
    
                 while(deque.size()!=0)deque.removeFirst();
                 deque.addLast(nums[k+i-1]);
            }
            //情况三:该元素大于队尾元素但小于等于队头元素,将小于此元素的队中元素从右边出队,此元素再入队
            else{
    
    
                while(deque.getLast()<nums[k+i-1])deque.removeLast();
                deque.addLast(nums[k+i-1]);
            }
            max[i]=deque.getFirst();
            System.out.println(max[i]);
        }
        return max;
    }
}

二、链表

22. 链表中倒数第k个节点[简单]

  输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public ListNode getKthFromEnd(ListNode head, int k) {
    
    
        ListNode p1=head,p2=head;
        while((--k)!=0){
    
    
            p2=p2.next;
        }
        while(p2.next!=null){
    
    
            p1=p1.next;
            p2=p2.next;
        }
        return p1;
    }
}

06. 从尾到头打印链表[简单]

  输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

	/**
	 * Definition for singly-linked list.
	 * public class ListNode {
	 *     int val;
	 *     ListNode next;
	 *     ListNode(int x) { val = x; }
	 * }
	 */
	class Solution {
    
    
	    public int[] reversePrint(ListNode head) {
    
    
	        if(head==null)return new int[0];
	        //此题目没有头指针,新建一个
	        ListNode h=new ListNode();
	        h.next=head;
	        //free用来指向插入结点,temp用来标记位置
	        ListNode free=head,temp=head;
	        int count=0;
	        //头插法逆置链表
	        while(temp!=null){
    
    
	            ++count;
	            temp=temp.next;
	            free.next=h.next;
	            h.next=free;
	            free=temp;
	        }
	        int[] result=new int[count];
	        temp=h.next;
	        for(int i=0;i<count;++i){
    
    
	            result[i]=temp.val;
	            temp=temp.next;
	        }
	        return result;
	    }
	}

24. 反转链表[简单]

	/**
	 * Definition for singly-linked list.
	 * public class ListNode {
	 *     int val;
	 *     ListNode next;
	 *     ListNode(int x) { val = x; }
	 * }
	 */
	class Solution {
    
    
	    public ListNode reverseList(ListNode head) {
    
    
	        if(head==null)return null;
	        ListNode h=new ListNode();
	        h.next=head;
	        ListNode free=head,temp=head;
	        while(temp!=null){
    
    
	            temp=temp.next;
	            //这里的判断很重要,没有就会报错
	            if(free!=head)free.next=h.next;
	            else free.next=null;
	            h.next=free;
	            free=temp;
	        }
	        return h.next;
	    }
	}

52. 两个链表的第一个公共节点[简单]

在这里插入图片描述

	/**
	 * Definition for singly-linked list.
	 * public class ListNode {
	 *     int val;
	 *     ListNode next;
	 *     ListNode(int x) {
	 *         val = x;
	 *         next = null;
	 *     }
	 * }
	 */
	public class Solution {
    
    
	    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    
    
	        if(headA==null||headB==null)return null;
	        ListNode a=headA,b=headB;
	        int count=0;
	        while(a!=b&&a!=null&&b!=null){
    
    
	            if(a.next==null&&count<2){
    
    
	                ++count;
	                a=headB;
	            }
	            else a=a.next;
	            if(b.next==null&&count<2){
    
    
	                ++count;
	                b=headA;
	            }
	            else b=b.next;
	        }
	        return a;
	    }
	}

18. 删除链表的节点[简单]

  给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。

	/**
	 * Definition for singly-linked list.
	 * public class ListNode {
	 *     int val;
	 *     ListNode next;
	 *     ListNode(int x) { val = x; }
	 * }
	 */
	class Solution {
    
    
	    public ListNode deleteNode(ListNode head, int val) {
    
    
	        if(head==null)return null;
	        ListNode h=new ListNode();
	        h.next=head;
	        ListNode temp=h;
	        while(temp!=null&&temp.next!=null){
    
    
	            if(temp.next.val==val)temp.next=temp.next.next;
	            temp=temp.next;
	        }
	        return h.next;
	    }
	}

25. 合并两个排序的链表[简单]

  输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

	/**
	 * Definition for singly-linked list.
	 * public class ListNode {
	 *     int val;
	 *     ListNode next;
	 *     ListNode(int x) { val = x; }
	 * }
	 */
	class Solution {
    
    
	    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    
    
	        if(l1==null)return l2;
	        if(l2==null)return l1;
	        //用h存放结果,free用于插入结点,tail指向h尾部
	        ListNode h=new ListNode();
	        ListNode free,tail;
	        //先找出第一个结点
	        if(l1.val<=l2.val){
    
    
	            h.next=l1;
	            l1=l1.next;
	            tail=h.next;
	            tail.next=null;
	        }
	        else{
    
    
	            h.next=l2;
	            l2=l2.next;
	            tail=h.next;
	            tail.next=null;
	        }
	        while(l1!=null&&l2!=null){
    
    
	            if(l1.val<=l2.val){
    
    
	                free=l1;
	                l1=l1.next;
	                free.next=null;
	                tail.next=free;
	                tail=tail.next;
	            }
	            else{
    
    
	                free=l2;
	                l2=l2.next;
	                free.next=null;
	                tail.next=free;
	                tail=tail.next;
	            }
	        }
	        //如果l1或l2中仍有结点
	        if(l1!=null){
    
    
	            tail.next=l1;
	        }
	        if(l2!=null){
    
    
	            tail.next=l2;
	        }
	        return h.next;
	    }
	}

三、树

27. 二叉树的镜像[简单]

  请完成一个函数,输入一个二叉树,该函数输出它的镜像。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public TreeNode mirrorTree(TreeNode root) {
    
    
        //当根结点为空或为叶结点
        if(root==null||(root.left==null&&root.right==null)){
    
    }
        //当有左右子结点
        else if(root.left!=null&&root.right!=null){
    
    
            TreeNode temp=root.left;
            root.left=mirrorTree(root.right);
            root.right=mirrorTree(temp);
        }
        //当只有左子结点
        else if(root.left!=null){
    
    
            root.right=mirrorTree(root.left);
            root.left=null;
        }
        //当只有右子结点
        else{
    
    
            root.left=mirrorTree(root.right);
            root.right=null;
        }
        return root;
    }
}

55 - I. 二叉树的深度[简单]

  输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public int maxDepth(TreeNode root) {
    
    
        int depth=0;
        //如果根结点为空
        if(root==null)depth=0;
        //如果根结点为叶结点
        else if(root.left==null&&root.right==null)depth=1;
        //如果只有左子树
        else if(root.right==null){
    
    
            depth=depth+1+maxDepth(root.left);
        }
        //如果只有右子树
        else if(root.left==null){
    
    
            depth=depth+1+maxDepth(root.right);
        }
        //如果左右子树都有
        else{
    
    
            depth=depth+1+Math.max(maxDepth(root.left),maxDepth(root.right));
        }
        return depth;
    }
}

54. 二叉搜索树的第k大结点[简单]【】

  给定一棵二叉搜索树,请找出其中第k大的节点。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    ArrayList<Integer> list;
    int k;
    public int kthLargest(TreeNode root, int k) {
    
    
        this.k=k;
        return  midSort(root);
    }
    //迭代法实现遍历二叉树:右、中、左
    public int midSort(TreeNode root){
    
    
        TreeNode p=root;
        Stack<TreeNode> stack=new Stack<>();
        while(p!=null||!stack.empty()){
    
    
            //一直走到最右下角的结点去
            while(p!=null){
    
    
                stack.push(p);
                p=p.right;
            }
            //当p为空,说明右下已经没有结点了,需要出栈了
            if(!stack.empty()){
    
    
                p=stack.pop();
                --k;
                if(k==0)return p.val;
                p=p.left;
            }
        }
        return -1;
    }
}

68 - II. 二叉树的最近公共祖先[简单]

  给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    
    
        //结点不存在
        if(root==null||p==null||q==null)return null;
        //有一个为根结点
        if(root==p||root==q)return root;
        
        TreeNode left=lowestCommonAncestor(root.left,p,q);
        TreeNode right=lowestCommonAncestor(root.right,p,q);
        //一左一右
        if(left!=null&&right!=null)return root;
        //在同一侧
        else if(left!=null)return left;
        else if(right!=null)return right;
        else return null;
    }
}

68 - I. 二叉搜索树的最近公共祖先[简单]

  给定一个搜索二叉树, 找到该树中两个指定节点的最近公共祖先。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    
    
        if(root==null||p==null||q==null)return null;
        if(root==p||root==q)return root;
        //如果都比根结点大
        if(p.val>root.val&&q.val>root.val)return lowestCommonAncestor(root.right,p,q);
        //如果都比根结点小
        else if(p.val<root.val&&q.val<root.val)return lowestCommonAncestor(root.left,p,q);
        //如果一个比根大,一个比根小
        else return root;
    }
}

32 - II. 从上到下打印二叉树 II[简单]

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public List<List<Integer>> levelOrder(TreeNode root) {
    
    
        if(root==null)return new LinkedList<List<Integer>>();
        LinkedList<TreeNode> que=new LinkedList<>();
        List<List<Integer>> ans=new LinkedList<List<Integer>>();
        que.add(root);
        while(que.size()!=0){
    
    
            LinkedList<Integer> item=new LinkedList<>();
            for(int i=que.size();i>0;--i){
    
    
                TreeNode node=que.removeFirst();
                item.add(node.val);
                if(node.left!=null)que.add(node.left);
                if(node.right!=null)que.add(node.right);
            }
            ans.add(item);
        }
        return ans;
    }
}

55 - II. 平衡二叉树[简单]

  输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public boolean isBalanced(TreeNode root) {
    
    
        //结点为空
        if(root==null)return true;
        //结点为叶结点
        else if(root.left==null&&root.right==null)return true;
        //其他
        else {
    
    
            boolean result=(depth(root.left)-depth(root.right))<=1&&(depth(root.left)-depth(root.right))>=-1;
            return result&&isBalanced(root.left)&&isBalanced(root.right);
        }
    }
    public int depth(TreeNode root){
    
    
        //如果结点为空
        if(root==null)return 0;
        //如果结点为叶结点
        else if(root.left==null&&root.right==null)return 1;
        else return 1+Math.max(depth(root.left),depth(root.right));
    } 
}

28. 对称的二叉树[简单]

  请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public boolean isSymmetric(TreeNode root) {
    
    
        //如果结点为空或为叶结点
        if(root==null||(root.left==null&&root.right==null))return true;
        //如果只有一个左/右子树
        else if(root.left==null||root.right==null)return false;
        //左右子树都存在
        else return symmetric(root.left,root.right);
            
    }
    public boolean symmetric(TreeNode node1,TreeNode node2){
    
    
        //先判断两结点值是否相等
        if(node1.val!=node2.val)return false;
        //result1和2分别用来记录node1.left和node2.right、node1.right和node2.left的对称情况
        boolean result1=false;boolean result2=false;
        if(node1.left==null&&node2.right==null)result1=true;
        else if(node1.left==null||node2.right==null)return false;
        else result1=symmetric(node1.left,node2.right);

        if(node1.right==null&&node2.left==null)result2=true;
        else if(node1.right==null||node2.left==null)return false;
        else result2=symmetric(node1.right,node2.left);

        return result1&&result2;
    }
}

四、数组

03. 数组中重复的数字[简单]

  找出数组中重复的数字。在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

class Solution {
    
    
    public int findRepeatNumber(int[] nums) {
    
    
        //辅助空间,用来记录数值是否重复出现,元素默认值都是false
        boolean[] count=new boolean[nums.length];
        //遍历nums
        for(int i=0;i<nums.length;++i){
    
    
            //先检查是否已经出现过了
            if(count[nums[i]])return nums[i];
            //如果没出现过,记录此次出现并进行下一步
            else count[nums[i]]=true;
        }
        return -1;
    }
}

53 - I. 在排序数组中查找数字 I[简单]

  统计一个数字在排序数组中出现的次数。

class Solution {
    
    
    public int search(int[] nums, int target) {
    
    
        if(nums==null||nums.length==0||target<nums[0]||target>nums[nums.length-1])return 0;

        int count=0;
        for(int i=0;i<nums.length&&nums[i]<=target;++i){
    
    
            if(nums[i]==target)++count;
        }
        return count;
    }
}

29. 顺时针打印矩阵[简单]??

53 - II. 0~n-1中缺失的数字[简单]

  一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。

	class Solution {
    
    
	    public int missingNumber(int[] nums) {
    
    
	        if(nums==null&&nums.length==0)return -1;
	        for(int i=0;i<nums.length;++i){
    
    
	            if(nums[i]!=i)return i;
	        }
	        return nums.length;
	    }
	}

57. 和为s的两个数字[简单]

  输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。

	//双指针
	class Solution {
    
    
	    public int[] twoSum(int[] nums, int target) {
    
    
	        if(nums==null||nums.length==0||target<=2*nums[0]||target>=2*nums[nums.length-1])return new int[0];
	
	        int index1=0,index2=nums.length-1;
	        while(index1<index2){
    
    
	            if(nums[index1]+nums[index2]<target)++index1;
	            else if(nums[index1]+nums[index2]>target)--index2;
	            else return new int[]{
    
    nums[index1],nums[index2]};
	        }
	
	        return new int[0];
	    }
	}

21. 调整数组顺序使奇数位于偶数前面[简单]

  输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。

	class Solution {
    
    
	    public int[] exchange(int[] nums) {
    
    
	        if(nums==null||nums.length==0)return new int[0];
	
	        int index1=0,index2=nums.length-1;
	        while(true){
    
    
	            while(index1<nums.length&&nums[index1]%2==1)++index1;
	            while(index2>=0&&nums[index2]%2==0)--index2;
	            if(index1>=nums.length||index2<0||index1>=index2)break;
	            else{
    
    
	                int temp=nums[index1];
	                nums[index1]=nums[index2];
	                nums[index2]=temp;
	            }
	        }
	        return nums;
	    }
	}

40. 最小的k个数[简单]

  输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

	class Solution {
    
    
	    public int[] getLeastNumbers(int[] arr, int k) {
    
    
	        if(arr==null||arr.length==0||k<=0||k>arr.length)return new int[0];
	        if(k<arr.length)Arrays.sort(arr);
	        int[] result=new int[k];
	        for(int i=0;i<k;++i){
    
    
	            result[i]=arr[i];
	        }
	        return result;
	    }
	}

11. 旋转数组的最小数字[简单]

  把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。

class Solution {
    
    
    public int minArray(int[] numbers) {
    
    
        Arrays.sort(numbers);
        return numbers[0];
    }
}

39. 数组中出现次数超过一半的数字[简单]

  数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。你可以假设数组是非空的,并且给定的数组总是存在多数元素。

	class Solution {
    
    
	    public int majorityElement(int[] nums) {
    
    
	        Arrays.sort(nums);
	        return nums[nums.length/2];
	    }
	}

五、串

58 - II. 左旋转字符串[简单]

  字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

  方法一:遍历

	class Solution {
    
    
    public String reverseLeftWords(String s, int n) {
    
    
        //特殊情况
        if(n<=0||n>=s.length())return s;
        return getSub(s,n,s.length()-1).append(getSub(s,0,n-1)).toString();
    }
    public StringBuilder getSub(String s,int index1,int index2){
    
    
        StringBuilder result=new StringBuilder();
        for(int i=index1;i<=index2;++i){
    
    
            result.append(s.charAt(i));
        }
        return result;
    }
}

  方法二:直接使用java库函数,效率更高。

class Solution {
    
    
    public String reverseLeftWords(String s, int n) {
    
    
        return s.substring(n)+s.substring(0,n);
    }
}

58 - I. 翻转单词顺序[简单]

  输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。

	class Solution {
    
    
	    public String reverseWords(String s) {
    
    
	        if(s==null||s.length()==0)return s;
	        //去除两端空格
	        s=s.trim();
	        StringBuilder result=new StringBuilder();
	        int index1=0;
	        for(int i=0;i<s.length();){
    
    
	            //遇到空格时
	            if(s.charAt(i)==' '){
    
    
	                String str=s.substring(index1,i);
	                StringBuilder temp=new StringBuilder();
	                temp.append(" ");
	                temp.append(str);
	                temp.append(result);
	                result=temp;
	                //跳过多个空格
	                while(s.charAt(i)==' '){
    
    
	                    ++i;
	                }
	                index1=i;
	            }
	            //走到尾端时
	            else if(i+1==s.length()){
    
    
	                String str=s.substring(index1,i+1);
	                StringBuilder temp=new StringBuilder();
	                temp.append(str);
	                temp.append(result);
	                result=temp;
	                break;
	            }
	            else ++i;
	        }
	        return result.toString();
	    }
	}

05. 替换空格[简单]

  请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

	class Solution {
    
    
	    public String replaceSpace(String s) {
    
    
	        if(s==null||s.length()==0)return s;
	        String str="%20";
	        StringBuilder result=new StringBuilder();
	        result=result.append(s);
	        for(int i=0;i<result.length();){
    
    
	            if(result.charAt(i)==' '){
    
    
	                result=result.replace(i,i+1,str);
	                i+=3;
	            }
	            else ++i;
	        }
	        return result.toString();
	    }
	}

六、数学问题

17. 打印从1到最大的n位数[简单]

	class Solution {
    
    
	    public int[] printNumbers(int n) {
    
    
	        if(n<1)return new int[0];
	        int size=(int)Math.pow(10,n)-1;
	        int[] result=new int[size];
	        for(int i=0;i<size;++i)result[i]=i+1;
	        return result;
	    }
	}

62. 圆圈中最后剩下的数字[简单]

  0,1,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

	class Solution {
    
    
	    public int lastRemaining(int n, int m) {
    
    
	        ArrayList<Integer> nums=new ArrayList<>(n);
	        for(int i=0;i<n;++i)nums.add(i);
	        int index=0;
	        while(nums.size()!=1){
    
    
	            index=(index+m-1)%nums.size();
	            nums.remove(index);
	        }
	        return nums.get(0);
	    }
	}

10- II. 青蛙跳台阶问题[简单]

  一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

class Solution {
    
    
    public int numWays(int n) {
    
    
        if(n==0||n==1)return 1;
        else if(n==2)return 2;
        else{
    
    
            int index1=1,index2=2;
            for(int i=3;i<=n;++i){
    
    
                int temp=(index1+index2)%1000000007;
                index1=index2;
                index2=temp;
            }
            return index2;
        }
    }
}

10- I. 斐波那契数列[简单]

  写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:

F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.

class Solution {
    
    
    public int fib(int n) {
    
    
        if(n==0)return 0;
        else if(n==1)return 1;
        else{
    
    
            int index1=0,index2=1;
            for(int i=2;i<=n;++i){
    
    
                int temp=(index1+index2)%1000000007;
                index1=index2;
                index2=temp;
            }
            return index2;
        }
    }
}

七、哈希表

50. 第一个只出现一次的字符[简单]

  在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

	class Solution {
    
    
	    public char firstUniqChar(String s) {
    
    
	        if(s==null||s.length()==0)return ' ';
	        char[] sc=s.toCharArray();
	        HashMap<Character,Boolean> map= new HashMap<>(s.length());
	        for(char c:sc){
    
    
	            if(!map.containsKey(c))map.put(c,false);
	            else if(!map.get(c))map.replace(c,false,true);
	            else{
    
    }
	        }
	        for(char c:sc){
    
    
	            if(!map.get(c))return c;
	        }
	        return ' ';
	    }
	}

61. 扑克牌中的顺子[简单]

  从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。

class Solution {
    
    
    public boolean isStraight(int[] nums) {
    
    
        if(nums==null||nums.length<5)return false;
        Set<Integer> repeat=new HashSet<>();
        int min=14,max=0;
        for(int num:nums){
    
    
            if(num==0)continue;
            else if(num<0||num>13)return false;
            else if(repeat.contains(num))return false;
            else {
    
    
                repeat.add(num);
                max=num>max?num:max;
                min=num<min?num:min;
            }
        }
        return max-min<5?true:false;
    }
}

八、动态规划

42. 连续子数组的最大和[简单]

  输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。

class Solution {
    
    
    public int maxSubArray(int[] nums) {
    
    
        int max=nums[0];
        for(int i=1;i<nums.length;++i){
    
    
            if(nums[i-1]>0)nums[i]+=nums[i-1];
            max=nums[i]>max?nums[i]:max;
        }
        return max;
    }
}

57 - II. 和为s的连续正数序列[简单]

  输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

class Solution {
    
    
    public int[][] findContinuousSequence(int target) {
    
    
        List<int[]> vec=new ArrayList<>();
        if(target==1)return new int[0][0];
        
        for(int index1=1,index2=2;index1<index2&&index2<target;){
    
    
            int sum=(index1+index2)*(index2-index1+1)/2;
            if(sum>target)++index1;
            else if(sum<target)++index2;
            else {
    
    
                int[] item=new int[index2-index1+1];
                for(int i=0;i<=index2-index1;++i)item[i]=index1+i;
                vec.add(item);
                ++index1;
            }
        }

        return vec.toArray(new int[vec.size()][]);
    }
}

九、位运算

65. 不用加减乘除做加法[简单]

  写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。

class Solution {
    
    
    public int add(int a, int b) {
    
    
        if(a==0)return b;
        if(b==0)return a;
        while(b!=0){
    
    
            int c=(a&b)<<1;
            a=a^b;
            b=c;
        }
        return a;
    }   
}

15. 二进制中1的个数[简单]

  请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

public class Solution {
    
    
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
    
    
       int count=0;
       while(n!=0){
    
    
           if((n&1)==1)++count;
           n = n>>>1;
       }
       return count;
    }
}

猜你喜欢

转载自blog.csdn.net/Tracycoder/article/details/112217258