画图让抽象形象化1+ 抽象建模能力2+举例让抽象具体化5

1. 顺时针打印矩阵

题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

链接:https://www.nowcoder.com/questionTerminal/9b4c81a02cd34f76be2659fa0d54342a
来源:牛客网

//主体循环部分才5行。其实是有规律可循的。将每一层的四个边角搞清楚就可以打印出来了
 
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> printMatrix(int [][] array) {
        ArrayList<Integer> result = new ArrayList<Integer> ();
        if(array.length==0) return result;
        int n = array.length,m = array[0].length;
        if(m==0) return result;
        int layers = (Math.min(n,m)-1)/2+1;//这个是层数
        for(int i=0;i<layers;i++){
            for(int k = i;k<m-i;k++) result.add(array[i][k]);//左至右
            for(int j=i+1;j<n-i;j++) result.add(array[j][m-i-1]);//右上至右下
            for(int k=m-i-2;(k>=i)&&(n-i-1!=i);k--) result.add(array[n-i-1][k]);//右至左
            for(int j=n-i-2;(j>i)&&(m-i-1!=i);j--) result.add(array[j][i]);//左下至左上
        }
        return result;       
    }
}
链接:https://www.nowcoder.com/questionTerminal/9b4c81a02cd34f76be2659fa0d54342a
来源:牛客网

import java.util.ArrayList;
public class Solution {
    ArrayList  a=new ArrayList();   new一个数组 以便下面函数能调用
    public ArrayList printMatrix(int [][] matrix) {
       int tR=0;
       int tC=0;
       int dR=matrix.length-1;
       int dC=matrix[0].length-1;
        while(tR<=dR&&tC<=dC){ 左上边界最多到达右下边界 用于判断是否还是剥圈打印
       printEdge(matrix,tR++,tC++,dR--,dC--);
        }
      return a;
    }
    public  void printEdge(int [][] m,int tR,int tC,int dR,int dC){
        if(tR==dR){    先判断是否只是一横行 如果是 打印该横行的列(通常用于内圈)
            for(int i=tC;i<=dC;i++){
                a.add(m[tR][i]);
            }
        }
        else if(tC==dC){  再判断是否只是一竖列 如果是 打印该横行的列(通常用于内圈
            for(int i=tR;i<=dR;i++){
                a.add(m[i][tC]);
            }
        }
        else {
            int curC=tC;用2个变量储存 用于判断当前位置
            int curR=tR;
            while(curC!=dC){      当前位置未到达当前行的最右列 --》往右去
                a.add(m[tR][curC]);
            curC++;
            }
            while(curR!=dR){      当前位置未到达当前列的最底行 --》往下去
                a.add(m[curR][dC]);
                curR++;
            }
            while(curC!=tC){      当前位置未到达当前行的最左列 --》往左去
                a.add(m[dR][curC]);
                curC--;
            }
            while(curR!=tR){      当前位置未到达当前列的最顶行 --》往上去
                a.add(m[curR][tC]);
                curR--;
            }
        }
    }
}

1. 扑克牌顺子

题目描述
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张_)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

链接:https://www.nowcoder.com/questionTerminal/762836f4d43d43ca9deb273b3de8e1f4
来源:牛客网

必须满足两个条件
1. 除0外没有重复的数
2. max - min < 5

public class Solution {
    public boolean isContinuous(int [] numbers) {
        if(numbers.length != 5) return false;
        int min = 14;
        int max = -1;
        int flag = 0;
        for(int i = 0; i < numbers.length; i++) {
            int number = numbers[i];
            if(number < 0 || number > 13) return false;
            if(number == 0) continue;
            if(((flag >> number) & 1) == 1) return false;
            flag |= (1 << number);
            if(number > max) max = number;
            if(number < min) min = number;
            if(max - min >= 5) return false;
        }
        return true;
    }
}
链接:https://www.nowcoder.com/questionTerminal/762836f4d43d43ca9deb273b3de8e1f4
来源:牛客网

1、排序 
2、计算所有相邻数字间隔总数 
3、计算0的个数 
4、如果2、3相等,就是顺子 
5、如果出现对子,则不是顺子

import java.util.Arrays;
public class Solution {
    public boolean isContinuous(int[] numbers) {
        int numOfZero = 0;
        int numOfInterval = 0;
        int length = numbers.length;
        if(length == 0){
           return false;
        }
        Arrays.sort(numbers);
        for (int i = 0; i < length - 1; i++) {
            // 计算癞子数量
            if (numbers[i] == 0) {
                numOfZero++;
                continue;
            }
            // 对子,直接返回
            if (numbers[i] == numbers[i + 1]) {
                return false;
            }
            numOfInterval += numbers[i + 1] - numbers[i] - 1;
        }
        if (numOfZero >= numOfInterval) {
            return true;
        }
        return false;
    }
}

2. 孩子们的游戏(圆圈中最后剩下的数)

题目描述
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数…这样下去…直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!_)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)

链接:https://www.nowcoder.com/questionTerminal/f78a359491e64a50bce2d89cff857eb6
来源:牛客网

    /*
    *这道题我用数组来模拟环,思路还是比较简单,但是各种下标要理清
    */
    public static int findLastNumber(int n,int m){
        if(n<1||m<1) return -1;
        int[] array = new int[n];
        int i = -1,step = 0, count = n;
        while(count>0){   //跳出循环时将最后一个元素也设置为了-1
            i++;          //指向上一个被删除对象的下一个元素。
            if(i>=n) i=0;  //模拟环。
            if(array[i] == -1) continue; //跳过被删除的对象。
            step++;                     //记录已走过的。
            if(step==m) {               //找到待删除的对象。
                array[i]=-1;
                step = 0;
                count--;
            }        
        }
        return i;//返回跳出循环时的i,即最后一个被设置为-1的元素
    }
链接:https://www.nowcoder.com/questionTerminal/f78a359491e64a50bce2d89cff857eb6
来源:牛客网

ava实现的话,可以使用LinkedList,考虑删除节点的效率。模拟游戏过程即可:


import java.util.LinkedList;
 
public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        LinkedList<Integer> list = new LinkedList<Integer>();
        for (int i = 0; i < n; i ++) {
            list.add(i);
        }
         
        int bt = 0;
        while (list.size() > 1) {
            bt = (bt + m - 1) % list.size();
            list.remove(bt);
        }
         
        return list.size() == 1 ? list.get(0) : -1;
    }
}
其实这是个约瑟夫环问题,但是绝对没必要去死记硬背数学公式,直接用链表模拟游戏过程即可。
链接:https://www.nowcoder.com/questionTerminal/f78a359491e64a50bce2d89cff857eb6
来源:牛客网

public class Solution {
    public int LastRemaining_Solution(int n, int m) {
         
        if(m <= 0 || n <= 0){
            return -1;
        }
        //先构造循环链表
        ListNode head = new ListNode(0); //头结点, 值为0
        ListNode pre = head;
        ListNode temp = null;
        for(int i = 1; i < n; i++){
            temp = new ListNode(i);
            pre.next = temp;
            pre = temp;
        }
        temp.next = head;//将第n-1个结点(也就是尾结点)指向头结点
         
        ListNode temp2 = null;
        while(n != 1){
            temp2 = head;
            //先找到第m个结点的前驱
            for(int i = 1; i < m - 1; i++){
                temp2 = temp2.next;
            }
            //删除第m个结点:将第m个结点的前驱指向第m个结点后面那个结点,temp2表示第m个结点的前驱
            temp2.next = temp2.next.next;
            head = temp2.next; //更新头结点
            n--;
        }
     
        return head.value;
         
    }
}
 
/**
 * 结点
 */
class ListNode {
    int value;
    ListNode next = null;
     
    public ListNode(int val) {
        this.value = val;
    }
}

1. 包含min函数的栈

题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

链接:https://www.nowcoder.com/questionTerminal/4c776177d2c04c2494f2555c9fcc1e49
来源:牛客网

import java.util.Stack;
 
public class Solution {
    Stack<Integer> dataStack = new Stack<Integer>();
    Stack<Integer> minStack = new Stack<Integer>();
     
        public void push(int node) {
        dataStack.push(node);
        if(minStack.isEmpty() || node < minStack.peek()){
            minStack.push(node);
        }
        else{
            minStack.push(minStack.peek());
        }
    }
 
    public void pop() {
        dataStack.pop();
        minStack.pop();
    }
 
    public int top() {
        return dataStack.peek();
    }
 
    public int min() {
        return minStack.peek();
    }
}

链接:https://www.nowcoder.com/questionTerminal/4c776177d2c04c2494f2555c9fcc1e49
来源:牛客网

import java.util.Stack;
 
思路:用一个栈data保存数据,用另外一个栈min保存依次入栈最小的数
比如,data中依次入栈,5,  4,  3, 8, 10, 11, 12, 1
       则min依次入栈,5,  4,  3,no,no, no, no, 1
 
no代表此次不如栈
每次入栈的时候,如果入栈的元素比min中的栈顶元素小或等于则入栈,否则不如栈。
 
public class Solution {
    Stack<Integer> data = new Stack<Integer>();
    Stack<Integer> min = new Stack<Integer>();
    Integer temp = null;
    public void push(int node) {
        if(temp != null){
            if(node <= temp ){
                temp = node;
                min.push(node);
            }
            data.push(node);
        }else{
            temp = node;
            data.push(node);
            min.push(node);
        }
    }
     
    public void pop() {
        int num = data.pop();
        int num2 = min.pop();
        if(num != num2){
           min.push(num2);
        }
    }
     
    public int top() {
        int num = data.pop();
        data.push(num);
        return num;
    }
     
    public int min() {
        int num = min.pop();
        min.push(num);
        return num;
    }
}
链接:https://www.nowcoder.com/questionTerminal/4c776177d2c04c2494f2555c9fcc1e49
来源:牛客网

import java.util.Stack;
import java.util.Arrays;
public class Solution {
/*借用辅助栈存储min的大小,自定义了栈结构
*/
    private int size;
    private int min = Integer.MAX_VALUE;
    private Stack<Integer> minStack = new Stack<Integer>();
    private Integer[] elements = new Integer[10];
    public void push(int node) {
        ensureCapacity(size+1);
        elements[size++] = node;
        if(node <= min){
            minStack.push(node);
            min = minStack.peek();
        }else{
            minStack.push(min);
        }
    //    System.out.println(min+"");
    }
 
    private void ensureCapacity(int size) {
        // TODO Auto-generated method stub
        int len = elements.length;
        if(size > len){
            int newLen = (len*3)/2+1; //每次扩容方式
            elements = Arrays.copyOf(elements, newLen);
        }
    }
    public void pop() {
        Integer top = top();
        if(top != null){
            elements[size-1] = (Integer) null;
        }
        size--;
        minStack.pop();    
        min = minStack.peek();
    //    System.out.println(min+"");
    }
 
    public int top() {
        if(!empty()){
            if(size-1>=0)
                return elements[size-1];
        }
        return (Integer) null;
    }
    public boolean empty(){
        return size == 0;
    }
 
    public int min() {
        return min;
    }
}

2. 二叉树中和为某一值的路径

题目描述
输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

链接:https://www.nowcoder.com/questionTerminal/b736e784e3e34731af99065031301bca
来源:牛客网

public class Solution {
    private ArrayList<ArrayList<Integer>> listAll = new ArrayList<ArrayList<Integer>>();
    private ArrayList<Integer> list = new ArrayList<Integer>();
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
        if(root == null) return listAll;
        list.add(root.val);
        target -= root.val;
        if(target == 0 && root.left == null && root.right == null)
            listAll.add(new ArrayList<Integer>(list));  //不重新new的话从始至终listAll中所有引用都指向了同一个一个
        FindPath(root.left, target);
        FindPath(root.right, target);
        list.remove(list.size()-1);
        return listAll;
    }
}
链接:https://www.nowcoder.com/questionTerminal/b736e784e3e34731af99065031301bca
来源:牛客网

这个还是比较简单的,经典的递归策略。
提供一个Java版本的:

import java.util.ArrayList;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
 
    public TreeNode(int val) {
        this.val = val;
 
    }
}
*/
public class Solution {
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
        ArrayList<ArrayList<Integer>> paths=new ArrayList<ArrayList<Integer>>();
        if(root==null)return paths;
        find(paths,new ArrayList<Integer>(),root,target);
        return paths;
    }
    public void find(ArrayList<ArrayList<Integer>> paths,ArrayList<Integer> path,TreeNode root,int target){
        path.add(root.val);
        if(root.left==null&&root.right==null){
            if(target==root.val){
                paths.add(path);
            }
            return;
        }
        ArrayList<Integer> path2=new ArrayList<>();
        path2.addAll(path);
        if(root.left!=null)find(paths,path,root.left,target-root.val);
        if(root.right!=null)find(paths,path2,root.right,target-root.val);
    }
}

3. 从上往下打印二叉树

题目描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。

链接:https://www.nowcoder.com/questionTerminal/7fe2212963db4790b57431d9ed259701
来源:牛客网

/**
思路是用arraylist模拟一个队列来存储相应的TreeNode
*/
public class Solution {
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        ArrayList<Integer> list = new ArrayList<>();
        ArrayList<TreeNode> queue = new ArrayList<>();
        if (root == null) {
            return list;
        }
        queue.add(root);
        while (queue.size() != 0) {
            TreeNode temp = queue.remove(0);
            if (temp.left != null){
                queue.add(temp.left);
            }
            if (temp.right != null) {
                queue.add(temp.right);
            }
            list.add(temp.val);
        }
        return list;
    }
}
链接:https://www.nowcoder.com/questionTerminal/7fe2212963db4790b57431d9ed259701
来源:牛客网

这不就是二叉树的层次遍历么,借助一个队列就可以了。
java版本:


public class Solution {
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        if(root==null){
            return list;
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode treeNode = queue.poll();
            if (treeNode.left != null) {
                queue.offer(treeNode.left);
            }
            if (treeNode.right != null) {
                queue.offer(treeNode.right);
            }
            list.add(treeNode.val);
        }
        return list;
    }
}

4. 二叉搜索树的后序遍历序列

题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

链接:https://www.nowcoder.com/questionTerminal/a861533d45854474ac791d90e447bafd
来源:牛客网

思路:找住二叉查找树的特点:左子树<根<=右子树  使用分治思想
public class Solution {
    public boolean VerifySquenceOfBST(int [] sequence) {
        if(sequence.length == 0){
            return false;
        }
        if(sequence.length == 1){
            return true;
        }
        return judge(sequence,0,sequence.length-1);
    }
     
    public boolean judge(int[] a,int start,int end){
        if(start >= end){
            return true;
        }
        int i = start;
        while(a[i] < a[end]){
            ++i;
        }
        for(int j=i;j<end;j++){
            if(a[j] < a[end]){
                return false;
            }
        }
        return judge(a,start,i-1) && judge(a,i,end-1);
    }
}

5. 栈的压入、弹出序列

题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

链接:https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106
来源:牛客网

【思路】借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。

举例:

入栈1,2,3,4,5

出栈4,5,3,2,1

首先1入辅助栈,此时栈顶1≠4,继续入栈2

此时栈顶2≠4,继续入栈3

此时栈顶3≠4,继续入栈4

此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3

此时栈顶3≠5,继续入栈5

此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3

….

依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。


import java.util.ArrayList;
import java.util.Stack;
public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
        if(pushA.length == 0 || popA.length == 0)
            return false;
        Stack<Integer> s = new Stack<Integer>();
        //用于标识弹出序列的位置
        int popIndex = 0;
        for(int i = 0; i< pushA.length;i++){
            s.push(pushA[i]);
            //如果栈不为空,且栈顶元素等于弹出序列
            while(!s.empty() &&s.peek() == popA[popIndex]){
                //出栈
                s.pop();
                //弹出序列向后一位
                popIndex++;
            }
        }
        return s.empty();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值