20201018:笔试题+算法题

错题一

  • What will happen when you attempt to compile and run the following code?

在这里插入图片描述

public class Test{
static{
   int x=5;
}
static int x,y;
public static void main(String args[]){
   x--;
   myMethod();
   System.out.println(x+y+ ++x);
}
public static void myMethod( ){
  	y=x++ + ++x;
 }
}

1、JVM加载class文件时,就会执行静态代码块,静态代码块中初始化了一个变量x并初始化为5,由于该变量是个局部变量,静态代码快执行完后变被释放;

2、声明了两个静态成员变量x,y,并没有赋初值,会有默认出值,int类型为0;

3、执行x--操作,变量单独进行自增或自减操作x----x的效果一样,此时x变为了-1;

4、调用MyMethod()方法,在该方法中对x和y进行计算,由于x和y都是静态成员变量,所以在整个类的生命周期内的x和y都是同一个;

5、y=x++ + ++x可以看成是y=(x++)+(++x),当++或者–和其它变量进行运算时,x++表示先运算,再自增,++x表示先自增再参与运算;所以此时x为-1参与运算,然后自增,x此时为0,++x后x为1,然后参与运算,那么y=-1+1就为0,此时x为1;

6、执行并打印x+y + ++x运算方式和第5步相同,最后计算结果就为3;

错题二

在这里插入图片描述

  • java 1.8开始支持接口中定义静态方法;

错题三

在这里插入图片描述

  • 所谓的释放锁资源实际是:通知对象内置的monitor对象进行释放,而只有所有对象都有内置的monitor对象,才能实现任何对象的锁资源都可以释放。

  • 又因为所有类都继承自Object,所以wait()就成了Object方法,也就是通过wait()来通知对象内置的monitor对象释放,而且事实上因为这涉及对硬件底层的操作,所以wait()方法是native方法,底层是用C写的;

  • 其他都是Thread所有,所以其他3个是没有资格释放资源的,而join()有资格释放资源其实是通过调用wait()来实现的;

代码如下: 
wait()方法    
    public final native void wait(long timeoutMillis) throws InterruptedException;

join()方法
public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

错题四

在这里插入图片描述

  • this()和super()为构造方法,作用是在JVM堆中构建出一个对象。因此避免多次创建对象,同一个方法内只能调用一次this()或super()。

  • 同时为了避免操作对象时对象还未构建成功,需要this()和super()的调用在第一行实现【以此来创建对象】,防止异常

错题五

  • 变量a是一个64位有符号的整数,初始值用16进制表示为:0x 7FFF FFFF FFFF FFFF;变量b是一个64位有符号的整数,初始值用16进制表示为:0x 8000 0000 0000 0000。则a+b的结果用10进制表示为多少?

在这里插入图片描述
1、a+b的16进制表示为:0x FFFF FFFF FFFF FFFF(16位F),转为2进制为111……111(64位1,每个F->4位2);

2、有符号数:是针对二进制来讲的。用最高位作为符号位,“0”代表“+”,“1”代表“-”。所以a+b的结果是一个负数。

3、计算机中负数是以补码的形式保存的,将补码转换成原码的计算方式如下:

    ①对于正数,原码与补码相同。
    ②对于负数,将补码除符号位之外,按位取反,末位加1,即得到原码。

4、a + b = 111……111(64位1)

      取反:100……000(1位1,后面63位0)
      加一:100……001(中间62位0)
      10进制:-1

算法一

  • 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。有效字符串需满足:

左括号必须用相同类型的右括号闭合;
左括号必须以正确的顺序闭合;
注意空字符串可被认为是有效字符串;

public boolean isValid(String s) {
    //1、如果当前元素是右括号:
    //      栈中没有元素,返回false;
    //      栈中最上面的元素不等于左括号,返回false
    
    //2、不符合上面的条件的,也就是栈中元素和当前元素匹配,,栈中最上面的元素弹栈
    
    //3、如果当前元素是左括号,进栈
    
    //4、最终返回栈是否为空

    int n = s.length();
    if (n % 2 == 1) {
        return false;
    }

    Map<Character, Character> pairs = new HashMap<Character, Character>() {{
        put(')', '(');
        put(']', '[');
        put('}', '{');
    }};
    Deque<Character> stack = new LinkedList<Character>();
    for (int i = 0; i < n; i++) {
        char ch = s.charAt(i);
        if (pairs.containsKey(ch)) {
            if (stack.isEmpty() || stack.peek() != pairs.get(ch)) {
                return false;
            }
            stack.pop();
        } else {
            stack.push(ch);
        }
    }
    return stack.isEmpty();
}

这个题目使用栈结构做最合适,上面是官方的解法;
他的核心思路就是:
1、遍历字符串并判断当前元素如果是右括号:

  • 栈中此时如果有元素不能匹配的返回false;
  • 栈中没有元素返回false;

2、否则的话就是栈中最上面的元素与当前右括号匹配,将该元素弹栈;
3、如果当前元素是左括号,进栈;
4、最终返回栈是否为空,如果为空代表都匹配上了,否则没有全部匹配;

算法二

  • 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

自己的做法:

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    if(l1 == null) {
        return l2;
    }
    if(l2 == null) {
        return l1;
    }

    LinkedList<Integer> list = new LinkedList<>();

    while (l1 != null) {
        list.add(l1.val);
        l1 = l1.next;
    }

    while (l2 != null) {
        list.add(l2.val);
        l2 = l2.next;
    }

    list.sort(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2 - o1;
        }
    });

    //System.out.println(list);
    //[1, 1, 2, 3, 4, 4]

    ListNode preNode = new ListNode(list.get(0));
    for (int i = 1; i < list.size(); i++) {
        ListNode listNode = new ListNode(list.get(i), preNode);
        preNode = listNode;
    }

    return preNode;
}

我的思路是:
1、首先判断如果给定的链表为空,返回另一个列表;
2、进行两次while循环,将其中所有的值放进LinkedList列表中;
3、利用LinkedList的sort()将所有的元素从大到小存放;
4、创建结点preNode,该结点的值是列表的第一个元素的值;
5、遍历列表,取出其中的每个值,并将上一个结点元素一起放进一个新的结点;
6、让preNode指向该结点;
7、这样,最终preNode指向的是最后一个结点,又因为列表元素是从大到小,所有最终返回preNode正好符合从小到大规则;

这个做法在内存上效率较高,但是时间上较低;学习了其他人的做法,代码如下:

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    if (l1 == null) {
        return l2;
    }
    else if (l2 == null) {
        return l1;
    }
    else if (l1.val < l2.val) {
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    }
    else {
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
}

采用递归的做法:
一个方法执行完,返回结点,该结点赋值给调用该方法的一个结点的next;

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值