Day02 复盘(一)

本文深入讲解了计算机基础知识,包括操作系统中的进程概念与管理、数据库事务并发处理问题、HTTP协议细节、二叉树特性、字符串算法等核心内容。

前言

作为自己春招笔试和面试的复盘,会进行一定的知识和题目的扩展。


一、杂例

1.OS:中进程的概念?为什么要引入进程?进程的通信方式有哪些?死锁的四个必要条件?

进程概念:

一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是系统进行资源分配和调度运行的基本单位,系统中一个进程由 程序数据集合进程控制块(PCB) 三部分组成。

引入:

早先的操作系统是单道批处理的,但是cpu是高效率的,而IO是低速的,就会出现cpu要等待IO的情况;从而降低了实际效率。后来就引入多道批处理;而程序在执行的过程中又会因为共享资源而导致程序在执行的过程中相互限制;所有后来引入进程用来给程序提供一个抽象的概念,他能申请道系统资源并且独立给程序提供资源,从而解决原来的程序之间因为资源共享而相互限制的问题。这样就可以提高系统资源的利用率以及系统的处理能力

进程的通信方式:

管道/匿名管道(Pipes) :用于具有亲缘关系的父子进程间或者兄弟进程之间的通信。
有名管道(Names Pipes) : 匿名管道由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道。有名管道严格遵循先进先出(first in first
out)。有名管道以磁盘文件的方式存在,可以实现本机任意两个进程通信。
信号(Signal) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;
消息队列(Message Queuing) :消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识。管道和消息队列的通信数据都是先进先出的原则。与管道(无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或者文件系统)不同的是消息队列存放在内核中,只有在内核重启(即,操作系统重启)或者显式地删除一个消息队列时,该消息队列才会被真正的删除。消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比
FIFO 更有优势。消息队列克服了信号承载信息量少,管道只能承载无格式字 节流以及缓冲区大小受限等缺点。
信号量(Semaphores) :信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。这种通信方式主要用于解决与同步相关的问题并避免竞争条件。
共享内存(Shared memory) :使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。可以说这是最有用的进程间通信方式。
套接字(Sockets) : 此方法主要用于在客户端和服务器之间通过网络进行通信。套接字是支持 TCP/IP 的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。

死锁的四个必要条件:

互斥:资源必须处于非共享模式,即一次只有一个进程可以使用。如果另一进程申请该资源,那么必须等待直到该资源被释放为止。
占有并等待:一个进程至少应该占有一个资源,并等待另一资源,而该资源被其他进程所占有。
非抢占:资源不能被抢占。只能在持有资源的进程完成任务后,该资源才会被释放。
循环等待:有一组等待进程 {P0, P1,…, Pn}, P0 等待的资源被 P1 占有,P1 等待的资源被 P2 占有,…,Pn-1 等待的资源被 Pn 占有,Pn 等待的资源被 P0 占有。
注意,只有四个条件同时成立时,死锁才会出现。

2.数据库的并发事务会带来什么问题?

脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。例如:事务 1 读取某表中的数据 A=20,事务 2 也读取 A=20,事务 1 修改 A=A-1,事务 2 也修改 A=A-1,最终结果A=19,事务 1 的修改被丢失。
不可重复读(Unrepeatable read): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

事务A事务B
修改(未提交)使用
修改修改
读----读修改
读----读插入

3.HTTP中GET和POST的区别?

GET在浏览器回退时是无害的,而POST会再次提交请求。 GET产生的URL地址可以被Bookmark,而POST不可以。
GET请求会被浏览器主动cache,而POST不会,除非手动设置。 GET请求只能进行url编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。 GET请求在URL中传送的参数是有长度限制的,而POST么有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。 GET参数通过URL传递,POST放在Request body中。

4.二叉树相关计算

1.n个节点的二叉树一共有((2n)!)/(n! * (n+1)!)种
2.n层二叉树的第n层最多为2^(n-1)个
3.二叉树节点计算公式 N = n0+n1+n2,度为0的叶子节点比度为2的节点数多一个。N=1n1+2n2+1
4.对任何一棵二叉树T,如果其终端节点数为n0,度为2的节点数为n2,则n0=n2+1
5.具有n个节点的完全二叉树的深度为log2(n) + 1
6.深度为h的二叉树最多有2^h-1个节点

二、算法

1.最长公共前缀

Leetcode: 编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 “”。
输入: [“flower”,“flow”,“flight”]
输出: “fl”
输入: [“dog”,“racecar”,“car”]
输出: “”
解释: 输入不存在公共前缀。

public class Main {
	public static String replaceSpace(String[] strs) {

		// 如果检查值不合法及就返回空串
		if (!checkStrs(strs)) {
			return "";
		}
		// 数组长度
		int len = strs.length;
		// 用于保存结果
		StringBuilder res = new StringBuilder();
		// 给字符串数组的元素按照升序排序(包含数字的话,数字会排在前面)
		Arrays.sort(strs);
		int m = strs[0].length();
		int n = strs[len - 1].length();
		int num = Math.min(m, n);
		for (int i = 0; i < num; i++) {
			if (strs[0].charAt(i) == strs[len - 1].charAt(i)) {
				res.append(strs[0].charAt(i));
			} else
				break;

		}
		return res.toString();

	}

	private static boolean chechStrs(String[] strs) {
		boolean flag = false;
		if (strs != null) {
			// 遍历strs检查元素值
			for (int i = 0; i < strs.length; i++) {
				if (strs[i] != null && strs[i].length() != 0) {
					flag = true;
				} else {
					flag = false;
					break;
				}
			}
		}
		return flag;
	}

	// 测试
	public static void main(String[] args) {
		String[] strs = { "customer", "car", "cat" };
		// String[] strs = { "customer", "car", null };//空串
		// String[] strs = {};//空串
		// String[] strs = null;//空串
		System.out.println(Main.replaceSpace(strs));// c
	}
}


2.替换空格

剑指offer:请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are
Happy.则经过替换之后的字符串为We%20Are%20Happy

//https://www.weiweiblog.cn/replacespace/
public class Solution {

  /**
   * 第一种方法:常规方法。利用String.charAt(i)以及String.valueOf(char).equals(" "
   * )遍历字符串并判断元素是否为空格。是则替换为"%20",否则不替换
   */
  public static String replaceSpace(StringBuffer str) {

    int length = str.length();
    // System.out.println("length=" + length);
    StringBuffer result = new StringBuffer();
    for (int i = 0; i < length; i++) {
      char b = str.charAt(i);
      if (String.valueOf(b).equals(" ")) {
        result.append("%20");
      } else {
        result.append(b);
      }
    }
    return result.toString();

  }

  /**
   * 第二种方法:利用API替换掉所用空格,一行代码解决问题
   */
  public static String replaceSpace2(StringBuffer str) {
    
    return str.toString().replaceAll("\\s", "%20");
  }
}


3.N进制加法题

import java.util.*;

public class N进制加法 {

    static String addByBase(String a, String b, int base) {

        StringBuffer ans = new StringBuffer();

        int n = Math.max(a.length(), b.length()), carry = 0;

        for (int i = 0; i < n; i++) {
            carry += i < a.length() ? (a.charAt(a.length() - 1 - i) - '0') : 0;
            carry += i < b.length() ? (b.charAt(b.length() - 1 - i) - '0') : 0;
            ans.append((char) (carry % base + '0'));
            carry /= base;
        }

        if (carry > 0) {
            ans.append('1');
        }
        ans.reverse();

        return ans.toString();
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String a = sc.next(); // 数字 a
        String b = sc.next(); // 数字 b
        int base = sc.nextInt(); // 进制
        System.out.println(addByBase(a, b, base));
    }

}

4.最长非重复子串长度

LeetCode:给定一个字符串s,请你找出其中不含有重复字符的 最长子串 的长度
解法引用自:https://blog.youkuaiyun.com/lfanchenyu/article/details/105890243

public static int lengthOfLongestSubstring(String s) {
        HashMap<Integer,Integer> map = new HashMap<Integer, Integer>();
        int length = s.length();
        int res = 0;//最终的长度
        int tmpRes = 0;//当前字符串下的不重复长度
        int flag = 0;//不重复子串开始的下标
        for(int i = 0; i < length; ++i){
            if(map.containsKey((int)s.charAt(i)) && map.get((int)s.charAt(i)) >= flag){
                flag = map.get((int)s.charAt(i)) + 1;
                if(tmpRes > res){
                    res = tmpRes;
                }
                tmpRes = i - flag + 1;
            }else {
                tmpRes++;
            }
            map.put((int)s.charAt(i), i);
        }
        return res > tmpRes ? res : tmpRes;
    }

5.细胞分裂问题(3次停止分裂)

蓝桥杯:有一个细胞,每一个小时分裂一次,一次分裂出一个新细胞,第三个小时分裂后会自然死亡。那么M(M<=20)个小时后有多少细胞?
解法引用自:https://blog.youkuaiyun.com/qq_41476060/article/details/103133321?spm=1001.2014.3001.5502
输入
输入的第一行包含一个正整数N,表示有N组测试数据;
接着是N行数据,每行包含一个正整数M,表示M小时。
输出
输出对应M小时后的细胞数量,每组数据的输出占一行。

输入

3
3
4
5

输出

7
13
24
import java.util.Scanner;
public class Cell {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int numb = sc.nextInt();
        for (int i = 0; i <numb; i++) {
            int M = sc.nextInt();
            int a=1,b=2,c=4,result = 1;
            if (M<3){
                for (int j=1; j <= M; j++) {
                    result = result*2;
                }
                System.out.println(result);
            }else {
                for (int k=3; k <= M; k++) {
                    result = a+b+c;
                    a = b;
                    b = c;
                    c = result;
                }
                System.out.println(result);
            }
        }
    }
}

6.扑克牌顺子问题

剑指Offer面试题 44:扑克牌的顺子 从扑克牌中随机抽 5 张牌,判断是不是顺子,即这 5 张牌是不是连续的。 2-10 为数字本身,A为 1,J 为 11,Q 为 12,K 为 13,而大小王可以看成任意的数字。
解法引用自:https://blog.youkuaiyun.com/qq_44822679/article/details/89520227
可以简要的根据大小王的数量0 1 2,判断间隔数

private static int getCountZero(int[] arr){
        int countZero = 0;
        for(int i=0;i<arr.length && arr[i] == 0;i++){
            countZero++;
//            if(arr[i] == 0){
//                countZero++;
//            }
        }
        if(countZero>2){
            //重新随机
            isSeries();
//            return false;
        }
        return countZero;
    }
    private static boolean isSeries(int[] arr){
        Arrays.sort(arr);
        //1.大小王个数
        int countZero = getCountZero(arr);

        //2.统计间隔数
        int countGrap = 0;
        for (int i = countZero;i<arr.length-1;i++){
            if(arr[i] == arr[i+1]){
                return false;
            }
            if(arr[i]+1 != arr[i+1]){
                //统计间隔数  0 0 1 2 3 4 9
                for(int j=arr[i];j<arr[i+1]-1;j++){
                    //
                    countGrap++;
                }
            }
        }
        if(countZero >= countGrap){
            return true;
        }
        return false;
    }
    public static void isSeries(){
        Random random = new Random();
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入牌个数");
        int count = scanner.nextInt();
        int[] arr = new int[count];
        for(int i=0;i<arr.length;i++){
            arr[i] = random.nextInt(14);//[0,14)
        }

        System.out.println(Arrays.toString(arr));
        boolean flag = isSeries(arr);
        if(flag){
            System.out.println("是顺子");
        }else{
            System.out.println("不是顺子");
        }
    }



评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值