牛客之程序员面试金典_ 编程题(二)

时间:2021-12-22 00:40:37

1.清除行列
题目描述
请编写一个算法,若N阶方阵中某个元素为0,则将其所在的行与列清零。

给定一个N阶方阵int[]”>mat和矩阵的阶数n,请返回完成操作后的int[][]方阵(C++中为vector>),保证n小于等于300,矩阵中的元素为int范围内。

测试样例:
[[1,2,3],[0,1,2],[0,0,1]]
返回:[[0,0,3],[0,0,0],[0,0,0]]

解答
首先遍历N阶方阵,使用两个一维boolean数组分别记录值为0的元素所在的行和列;
将方阵中对应的行和列清0。

import java.util.*;

public class Clearer {
    public int[][] clearZero(int[][] mat, int n) {
        boolean[] hang = new boolean[n];
        boolean[] lie = new boolean[n];

        for(int i = 0;i<n;i++){
            hang[i] = false;
            lie[i] = false;
        }

        for(int i = 0;i<n;i++){
            for(int j = 0;j<n;j++){
                if(mat[i][j]==0){
                    hang[i] = true;
                    lie[j] = true;
                }
            }
        }

        for(int i = 0;i<n;i++){
            for(int j = 0;j<n;j++){
                if(hang[i]||lie[j]){
                    mat[i][j] = 0;
                }
            }
        }

        return mat;
    } 
}

2.翻转子串
题目描述
假定我们都知道非常高效的算法来检查一个单词是否为其他字符串的子串。请将这个算法编写成一个函数,给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成,要求只能调用一次检查子串的函数。

给定两个字符串s1,s2,请返回bool值代表s2是否由s1旋转而成。字符串中字符为英文字母和空格,区分大小写,字符串长度小于等于1000。

测试样例:
“Hello world”,”worldhello ”
返回:false
“waterbottle”,”erbottlewat”
返回:true

这道题,我感觉题目描述方式很奇怪,无法正确理解到底是要是什么;
应该是想要判断s2是否是s1中的字符循环移位得来的。

解答:
很巧妙的一个解法,将两个s1连接起来,判断s2是否其子串即可。
import java.util.*;

public class ReverseEqual {
public boolean checkReverseEqual(String s1, String s2) {
// write code here
if(s1.length()!=s2.length())
return false;

    return (s1+s1).contains(s2);


}

}

3.找到链表中倒数第k个节点
解法一:首先遍历该链表计算链表的长度length,正数第length+1-k个即为倒数第k个元素

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {
        if(head == null){
            return head;
        }
        ListNode tmp = new ListNode(0);
        tmp.next = head;

        int length = 1;
        while(head.next != null){
            length++;
            head = head.next;
        }

        if(k>length)
            return head.next;

        head = tmp.next;
        int i = 1;
        while(i < (length+1-k)){
            head = head.next;
            i++;
        }

        return head;

    }
}

解法二:
使用两个指针s1和s2,s1先走k-1步,接着两个指针同时走,当s1走到链表尾部时,s2也就指向了倒数第k个元素。
因为如果队列有n个元素的话,从头走到为需要n-1步,从头走到倒数第k个元素需要走n-k补,所以就先让第一个指针走n-1-(n-k) = k-1步。

3.单个节点的删除
题目描述
实现一个算法,删除单向链表中间的某个结点,假定你只能访问该结点。

给定带删除的节点,请执行删除操作,若该节点为尾节点,返回false,否则返回true

这个题目系统判断有问题,不管是否删除,只要返回是正确的就判AC。

解答:
对于单链表来说,其只能知道其后置节点,而不知道前置,所以删除p的方法是,将p.next.val赋值给p.val,然后将p指向p.next.next;
(其实我觉得这个有点像单纯的改变了p的值,但没有真正的删除它,所以暂时mart一下)

import java.util.*;

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Remove {
    public boolean removeNode(ListNode pNode) {
        if(pNode == null | pNode.next == null)
            return false;
        pNode.val = pNode.next.val;
        pNode.next = pNode.next.next;
        return true;
    }
}

4.链表分割
题目描述
编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前

给定一个链表的头指针 ListNode* pHead,请返回重新排列后的链表的头指针。注意:分割以后保持原来的数据顺序不变。

解答:
设置两个空表l1和l2,当pHead.val

import java.util.*;

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Partition {
    public ListNode partition(ListNode pHead, int x) {
        // write code here
        if(pHead == null||pHead.next == null){
            return pHead;
        }
        ListNode l1 = new ListNode(-1);
        ListNode l2 = new ListNode(-1);
        ListNode tmp1 = l1;
        ListNode tmp2 = l2;

        while(pHead!=null){
            if(pHead.val<x){
                l1.next = new ListNode(pHead.val);
                l1 = l1.next;
            }
            else{
                l2.next = new ListNode(pHead.val);
                l2 = l2.next;
            }
            pHead = pHead.next;
        }
        l1.next = tmp2.next;
        return tmp1.next;
    }

}

5.链式A+B
题目描述
有两个用链表表示的整数,每个结点包含一个数位。这些数位是反向存放的,也就是个位排在链表的首部。编写函数对这两个整数求和,并用链表形式返回结果。

给定两个链表ListNode* A,ListNode* B,请返回A+B的结果(ListNode*)。

测试样例:
{1,2,3},{3,2,1}
返回:{4,4,4}

解答:
在判断链表当前节点是否为空的前提下,将对应节点上的val相加,并需要判断是否>10。
注意的地方时,对应为上的计算结果除以10赋给下一位,取余为当前位上的val;
在最后一位计算的结果同样需要判断。

import java.util.*;
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Plus {
    public ListNode plusAB(ListNode a, ListNode b) {
        // write code here
        ListNode re = new ListNode(0);
        ListNode tmp = re;
        while(a!=null||b!=null){
            re.next = new ListNode(re.val/10);
            re.val = re.val%10;
            re = re.next;
            if(a!=null){
                re.val +=a.val;
                a = a.next;
            }
            if(b!=null){
                re.val +=b.val;
                b = b.next;
            }
        }
        //判断最高位是否需要进位
        if(re.val>=10){
            re.next = new ListNode(re.val/10);
            re.val = re.val%10;

        }


        return tmp.next;
    }
}

6.回文链表
题目描述
请编写一个函数,检查链表是否为回文。

给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文。

测试样例:
{1,2,3,2,1}
返回:true
{1,2,3,2,3}
返回:false

解法:
遍历链表将其放入到一个数组中,然后从后往前遍历数组元素的值和链表中的值是否一次相等;
这里我使用的是普通的数组,需要先得出链表的长度才能够new一个数组出来,如果使用ArrayList,则便不需要了,因为它是动态分配内存空间的。

import java.util.*;

/* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/
public class Palindrome {
    public boolean isPalindrome(ListNode pHead) {
        if(pHead==null||pHead.next==null)
            return true;
        ListNode tmp = pHead;
        int num = 0;
        while(pHead!=null){
            num++;
            pHead = pHead.next;
        }
        int[] a = new int[num];
        pHead = tmp;
        for(int i = 0;i<num;i++){
            a[i] = pHead.val;
            pHead = pHead.next;
        }
        pHead = tmp;
        for(int i = num-1;i>=0;i--){
            if(a[i]!=pHead.val)
                return false;
            pHead = pHead.next;
        }
        return true;   
    }
}