剑指offer

1、二维数组的查找

题目描述

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

思路

思路1:

暴力解--遍历整个数组,时间复杂度为O(n*n)

思路2:对每一行来说,都是单调递增的数组,利用二分法,查找每一行,时间复杂度为O(n*logn)

public boolean Find(int target, int [][] array) {
   
    for(int i = 0; i < array.length; i++){
        int low = 0;
        int high = array[i].length - 1;
        while(low <= high){
            int mid = low + (high - low) >> 1;
            if(target > array[i][mid])
                low = mid + 1;
            else if(target < array[i][mid])
                high = mid - 1;
            else
                return true;
        }
    }
    return false;
}

思路3:考虑数组从左到右递增,从上到下递增,比较target与右上或左下的值 array[row][col]. target >array[row][col],表示target处在当前元素所在列的下边;target <array[row][col],表示target处在当前元素所在行的左边;

public boolean Find(int target, int [][] array) {

    int row = 0;
    int col = array[0].length - 1;
    while(row <= array.length - 1 && col >= 0){
        if(target == array[row][col])
            reurn true;
        else if(target > array[row][col])
            row++;
        else
            col--;
    }
}

 2、替换空格

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

思路1:

新建一个string,若要方便添加元素,则创建一个StringBuilder.。遇到空格添加三个字符‘%’,‘2’,‘0’。

public String replaceSpace(StringBuffer str) {
    if(str == null)
        return null;
    StringBuilder  newstr = new StringBuilder();
    for(int i = 0; i < str.length(); i++){
        if(str.charAt(i) == ' '){
            newstr.append('%');
            newstr.append('2');
            newstr.append('0');
        }else
            newstr.append(str.charAt(i));
        
    }
    return newstr;
}

思路2:

在原字符串上重新建立新串。首先需要计算新串的长度,然后按倒序的将字符加进新串。

public String replaceSpace(StringBuffer str) {
    if(str == null)
        return null;

    //计算空格的个数
    int spaceNum = 0;
    for(int i = 0; i < str.length; i++){
        if(str.charAt(i) == ' ')
            spaceNum++;
    }
    //定义字符串的新长度
    int len = str.length;
    int newLen = len + spaceNum * 2;
    str.setLength(newLen);

    for(int i = len - 1; i >= 0; i--){
        if(str.charAt(i) == ' '){
            str.setCharAt(newLen--, '0');
            str.setCharAt(newLen--, '2');
            str.setCharAt(newLen--, '%');
        }else{
            str.setCharAt(newLen--, str.charAt(i));
        }
    }
    return str.toString();
}

 3、从尾到头打印链表

题目描述

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

思路

思路1:利用递归,一致低轨道链表结尾,在返回时加入数值。

ArrayList<Integer> list = new  ArrayList<Integer>();
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
    if(listNode != null){
        ArrayList<Integer> printListFromTailToHead(listNode.next);
        list.add(listNode.val);
    }
}

思路2:利用栈,先将链表中的元素压进栈,然后一个一个出栈添加进链表。

public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
       ArrayList<Integer> a = new ArrayList<Integer>();
       Stack stack = new Stack();
       while(listNode != null){
           stack.push(listNode);
           listNode = listNode.next;
       }
       while(!stack.isEmpty()){
           a.add(stack.pop());
       }
       return a;
}

 思路3: 逆转链表,首先记住当前节点的next节点,然后将当前节点指向前一节点,然后更新当前节点为pre节点,next节点为当前节点。

public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
    ArrayList<Integer> list=new ArrayList<Integer>();
    ListNode pre = null;
    ListNode next = null;
    while(listNode != null){
        next = listNode.next;
        listNode.next = pre;
        pre = listNode;
        listNode = next;
    }
    while(pre != null){
        list.add(pre.val);
        pre = pre.next;
    }
    return list;
}

4、重建二叉树

题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

思路

先序遍历第一个位置肯定是根节点node,中序遍历的根节点位置在中间p,在p左边的肯定是node的左子树的中序数组,p右边的肯定是node的右子树的中序数组;另一方面,先序遍历的第二个位置到p,也是node左子树的先序子数组,剩下p右边的就是node的右子树的先序子数组,把四个数组找出来,分左右递归调用即可。

public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
    if(pre.length != in.length || pre.length == 0 || in.length == 0)
        return null;
    //先序遍历第一个值肯定是头节点
    TreeNode root = new TreeNode(pre[0]);

    //在中序遍历中找到和头节点相同的值的位置,依此位置划分左右子树
    int index = 0;
    while(in[index] != root.val)
        index++;

    //定义四个左右子树数组
    int[] preleft = new int[index + 1];
    int[] inleft = new int[index + 1];
    int[] preright = new int[pre.length - index - 1];
    int[] inright = new int[in.length - index - 1];

    for(int i = 0; i < in.length; i++){
        if(i < index){
            preleft = pre[i];
            inleft = in[i];
        }else{
            preright[j - i - 1] = pre[j];
            inright[j - i - 1] = in[j];
    }

    root.left = reConstructBinaryTree(preleft, inleft);
    root.right = reConstructBinaryTree(preright, inright);
    return root;
    }
}

5、用两个栈实现队列

题目描述

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

思路

一个栈用来做push操作,一个栈用来做pop()操作。这时需要注意,只有当pop栈是空的时候,push栈才能往里压元素,非空的时候直接返回pop栈的最上面的一个节点。

Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();  
    public void push(int node) {
        stack1.push(node);
    }
    
    public int pop() {
        if(!stack2.isEmpty()){
           return stack2.pop();
        }
        if(stack1 == null){
            return 0;
        }else{
            while(!stack1.isEmpty()){
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }

6、旋转数组的最小数字

题目描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

思路

思路1:直接遍历数组,找到第一个前面的数大于后面的数,返回后面的数即可。时间复杂度为O(n)。

public int minNumberInRotateArray(int [] array) {
        int y=0;
        for(int i=0;i<array.length;i++){
            if(array[i]>array[i+1]){
                y=array[i+1];
                break;
            }
              
        }
        return y;
    }
}

思路2:使用二分查找,比较中间元素和两头的值的大小,确定在哪一部分。时间复杂度O(logn)。

第一种情形:array[mid] > array[hi] -- lo  = mid + 1;

第二种情形:array[mid] == array[hi] -- 不能确定最小值是在mid左边还是右边,hi = hi - 1;

第三种情形:array[mid] < array[hi] -- hi = mid,只剩两个数的时候。mid会在lo的位置,所以返回array[lo];

public int minNumberInRotateArray(int [] array) {
        //二分查找
        if(array.length == 0)
            return 0;
        int lo = 0;
        int hi = array.length - 1;
        while(lo < hi){
            int mid = lo + ((hi - lo) >> 1);
            if(array[mid] > array[hi]){
                lo = mid + 1;
            }else if(array[mid] == array[hi]){
                hi = hi - 1;
            }else
                hi = mid;
        }
        return array[lo];  
    }

 7、斐波那契数列

题目描述

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。n<=39

思路

前两个数和是下一个数,为了保证时间复杂度为O(n)和空间复杂度为O(1)。采用非递归版本

public int Fibonacci(int n) { //非递归版本
        if(n == 0 || n ==1)
            return n;
        int res = 0;
        int pre = 1;
        int prepre = 0;
        for(int i = 1;i < n; i++){
            res = prepre + pre;
            prepre = pre;
            pre = res;
        }
        return res;
    }
public int Fibonacci(int n) { 非递归版本
    if(n == 0 || n ==1)
          return n;
    if(n == 2)
          return 1;
    return Fibonacci(n - 1) + Fibonacci(n - 2);
}

8、跳台阶

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

思路

考虑target-1,有多少中方案到target-1,就有多少中方案到target;考虑target-2,有多少中方案到target-2,就有多少中方案到target;将以上两种情况加起来就是答案f(target)=f(target-1)+f(target-2),即是斐波那契数列

public int Fibonacci(int n) { //非递归版本
        if(n == 0 || n ==1)
            return n;
        int res = 0;
        int pre = 1;
        int prepre = 0;
        for(int i = 1;i < n; i++){
            res = prepre + pre;
            prepre = pre;
            pre = res;
        }
        return res;
    }

 9、变态跳台阶

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

思路

因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级。跳1级,剩下n-1级,则剩下跳法是f(n-1);跳2级,剩下n-2级,则剩下跳法是f(n-2);所以f(n)=f(n-1)+f(n-2)+...+f(1),因为f(n-1)=f(n-2)+f(n-3)+...+f(1), 所以f(n)=2*f(n-1)

 public int JumpFloorII(int target) {
       
        return (int)Math.pow(2,target - 1);
}

10、矩形覆盖

题目描述

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

思路:这个问题依旧是斐波那契数列问题,考虑最边上要么竖着放一块,要么横着放2块,可以扩展到(1*m覆盖m*n区域)问题。

public int RectCover(int target) {  
        //归纳法--依旧是斐波那契数列
        //如果用1*m的方块覆盖m*n区域,递推关系式为f(n) = f(n-1) + f(n-m),(n > m)
        if(target < 1)         
            return 0;
        if(target == 1 || target == 2)
            return target;
        int res = 2;
        int pre = 1;
        int tmp = 0;
        for(int i = 3;i <= target;i++){
            tmp = res;
            res = res + pre;
            pre = tmp;
        }
        return res;
    }

11、二进制中1的个数

题目描述

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

思路

将整数转化为二进制字符串

public int NumberOf1(int n) {
        int count=0;
        String result=Integer.toBinaryString(n);  //把整数转换成二进制数
        for(int i=0;i<result.length();i++){
            if(result.charAt(i)=='1')
                count++;           
        }
        return count;        
    }

12、数值的整数次方

题目描述

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

思路

考虑指数的正负

public double Power(double base, int exponent) {
        double result=1.0;
        if(base==0.0) return 0;
        if(exponent>0)
             for(int i=0;i<exponent;i++){
                  result=result*base;
             }
        if(exponent<0){
            double basenew=1/base;
            int exponentnew=-exponent;
            for(int i=0;i<exponentnew;i++){
                  result=result*basenew;
             }
        }          
        if(exponent==0)
            result=1;
        return result;
  }

 13、调整数组顺序使奇数位于偶数前面

题目描述

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变

思路

思路1:判断奇数和偶数的条件是i % 2是否等于0,另开辟一个新的数组,奇数从前往后放,偶数从后往前放,遍历完数组后,将奇数放回按顺序放回原数组,偶数倒序放回。

思路2:类似冒泡算法,前偶后奇就交换

//思路1:这里可以改成遍历一回
public void reOrderArray(int [] array) {
        int [] a=new int[array.length];
        int count=0;
        for(int i=0;i<array.length;i++){
            if(array[i]%2==1){
                a[count]=array[i];
                count++;
            }
        }
        for(int i=0;i<array.length;i++){
            if(array[i]%2==0){
                a[count]=array[i];
                count++;
            }
        }
        for(int i=0;i<array.length;i++){
            array[i]=a[i];
        }
    }
//思路2
 public void reOrderArray(int [] array) {
       for(int i= 0;i<array.length-1;i++){
            for(int j=0;j<array.length-1-i;j++){
                if(array[j]%2==0&&array[j+1]%2==1){
                    int t = array[j];
                    array[j]=array[j+1];
                    array[j+1]=t;
                }
            }
        }
    }
//思路2另一种写法
public void reOrderArray(int [] array) {
        //相对位置不变,稳定性
        //插入排序的思想
        int m = array.length;
        int k = 0;//记录已经摆好位置的奇数的个数
        for (int i = 0; i < m; i++) {
            if (array[i] % 2 == 1) {
                int j = i;
                while (j > k) {//j >= k+1
                    int tmp = array[j];
                    array[j] = array[j-1];
                    array[j-1] = tmp;
                    j--;
                }
                k++;
            }
        }
    }

14、链表中倒数第k个结点

题目描述

输入一个链表,输出该链表中倒数第k个结点。

思路

先遍历链表统计节点个数,然后计算从前往后是第几个,输出即可。

public ListNode FindKthToTail(ListNode head,int k) {
        ListNode h=head;
        if(h==null)
            return null;
        int count=1;
        while(h.next!=null){
            count++;
            h=h.next;
        }
        int t=count-k+1;
         ListNode h2=head;
        for(int i=1;i<=count;i++){       
            if(i==t)
                break;
            h2=h2.next;
        }
        return h2;
    }

栈的压入、弹出序列

题目描述

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

思路

使用栈,对于压入数据使用栈,需要判断弹出数据是否和栈顶数据相同,相同的话就弹出栈顶数据,同时判断弹出数据的下一个,否则则继续压入数据,直到压入数据用完。

public boolean IsPopOrder(int [] pushA,int [] popA) {

    if(pushA == null || popA == null)
        return false;
    Stack<Integer> stack = new Stack<>();
    int i = 0;  //pushA的指针
    int j = 0;  //popA的指针
    stack.push(pushA[i++]);
    while(j < popA.length){
        while(popA[i] != stack.peek()){
            if(i == pushA.length)
                return false;
            stack.push(pushA[i++]);
        }
        j++;
        stack.pop();
    }
    return stack.empty();
}

二叉搜索树与双向链表

题目描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

思路

二叉搜索树的特点是左子节点小于父节点,右子节点大于父节点。要想按照排序组成双向链表,只需要按照树的中序遍历的顺序调整节点之间的指针即可。

public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;
}
public TreeNode Convert(TreeNode root){
    if(root == null)
        return root;
    Stack<TreeNode> stack = new Stack<>();
    TreeNode head = root;
    TreeNode pre = null;
    boolean flag = true;  //找到最左边的节点
    while(root != null || !stack.isEmpty()){
        while(root != null){  //找到最左的节点
            stack.push(root);
            root = root.left;
        }
        root = stack.pop();
        if(flag){
            head = root;
            pre = head;
            flag = false;
        }else{
            pre.right = root;
            root.left = pre;
            pre = root;
        }
        root = root.right;
    }
    return head;
}

字符串的排列

题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

输入描述:输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

思路

字符串的每一个位置都要和其他位置进行交换

public ArrayList<String> Permutation(String str) {
    ArrayList<String> list = new ArrayList<>();
    if(str == null || str.length() == 0)
        return list;
    char[] s = str.toCharArray();
    process(s, 0, list);
    return list;
}
public void process(char[] str, int i, ArrayList<String> list){
    //停止条件
    if(i == str.length - 1){
        if(!list.contains(String.valueof(str)))
            list.add(String.valueof(str));
    }
    for(int j = i; j < str.length; j ++){
        swap(str, i, j);
        process(str, i + 1, list);
        swap(str, i, j);
    }
}
public void swap(char[] str, int i, int j){
    char c = str[i];
    str[i] = str[j];
    str[j] = c;
} 

数组中出现次数超过一半的数字

题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

思路

方法一:使用HashMap,统计各个数字出现的次数,然后遍历找到出现次数超过一半的数字。

方法二:利用哪个数字出现的次数超过一半的特点,先假设是第一个数,依次遍历后面的数和它比较,相等则它的数量加1,不等则减一,若是等于0,说明不是这个数,将要比较的数设为当前值,然后继续比较后面的数。最后再遍历整个数组确认一下是找到的那个值。

public int MoreThanHalfNum_Solution(int [] array) {
    if(array.length < 1 || array == null)
        return 0;
    int target = array[0];  //先将目标定为第一个数
    int count = 1;  //第一个数的起始数量为1
    for(int i = 1; i < array.length; i ++){
        if(target != array[i]){
            count--;
        }else{
            count++;
        }
        if(count == 0){
            target = array[i];
            count = 1;
        }
    }
    //对目标进行确认
    count = 0;
    for(int i = 0; i < array.length; i ++){
        if(target == array[i]){
            ++count;
        }
        if(count > array.length / 2)
             return target;
    }
    return 0;
}

最小的K个数

题目描述

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

思路

方法一:直接使用排序

方法二:使用小根堆和大根堆

方法三:先假设前K个是最小的数,然后遍历剩下的数,如果比前K个数中的最大值小则进行替换;

public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
    ArrayList<Integer> list = new ArrayList<>();
    if(input.length == 0 || k < 0 || k > input.length )
        return list;
    //先将前K个数保存在list中
    for(int i = 0; i < k; i ++)
        list.add(input[i]);
    int tmp = 0;
    for(int i = k; i < input.length; i ++){
        tmp = getMaxOfList(list);
        if(input[i] < list.get(tmp)){
            list.set(tmp, input[i]);
        }
    }
    return list;
}
public int getMaxOfList(ArrayList<Integer> list){
    int max = Integer.MIN_VALUE;
    int index = 0;
    for(int i = 0; i < list.size(); i ++){
        if(list.get(i) > max){
            max = list.get(i);
            index = i;        
        }
    }
    return index;
}

连续子数组的最大和

题目描述

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

思路

检查当前和加上下一个数和下一个数的大小(因为当前和可能是负数),得出较大值保存下来,最后找到较大值中最大的值。

public int FindGreatestSumOfSubArray(int[] array) {
    
    if(array.length == 0 || array == null)
        return 0;
    int max = array[0];
    int res = array[0];
    for(int i = 1; i < array.length; i ++){
        max = Math.max(max + array[i], array[i]);
        res = Math.max(max, res);
    }
    return res;
}

整数中1出现的次数

题目描述

求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

思路

分别考虑当前位(个十百千)1的个数,然后将各个位1的个数加起来。

以百位为例:可能为0,1,2-9

为0时:12013中百位为1的个数为100-199、1100-1199、2100-2199、... 、10100-10199、11100-11199,一共12*100个,受高位影响;

为1时:12113中百位为1的个数为100-199、1100-1199、2100-2199、... 、10100-10199、11100-11199,一共12*100个,除了这些,还有12100-12113,一共14 = 13 + 1,此时不仅受高位影响还受低位影响;

为2-9时:12213中百位为1的个数为100-199、1100-1199、2100-2199、... 、10100-10199、11100-11199、12100-12199,一共13*100个,此时受高位(高位+1)影响;

public int NumberOf1Between1AndN_Solution(int n){
     if(n < 1)
        return 0;
    int count = 0; //计数
    //需要定义三个变量:高位数、当前位数、低位数
    int high = 0, cur = 0, low = 0;
    //定义一个位数变量
    int i = 1;
    while(n / i > 0){
        high = n / (i * 10);
        cur = (n / i) % 10;
        low = n - (n / i) * i;
        if(cur == 0){
            count += high * i;
        }else if(cur == 1){
            count += high * i + low + 1;
        }else{
            count += (high + 1) * i;
        }
        i = i * 10;
    }
    return count;
}

把数组排成最小的数

题目描述

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323

思路

实现一个比较器:对于字符串str1和字符串str2,str1 + str2  >  str2 + str1,则让str1 + str2在前面

public String PrintMinNumber(int [] numbers) {
    if(numbers == null || numbers.length < 1)
        return "";
    //先将数字转化为字符串格式
    String[] str = new String[numbers.length];
    for(int i = 0; i < numbers.length; i ++){
        str[i] = String.valueof(numbers[i]);
    }
    return smallestNumber(str);
}
//定义一个比较器
public class myComparator implements Camparator<String>{
    
    public int compare(String o1, String o2){
        return (o1 + o2).compareTo(o2 + o1);
    }
}

public String smallestNumber(String[] str){
    if(str.length() == 0 || str == null)
        return "";
    Arrays.sort(str, new myComparator());
    String res = "";
    for(int i = 0; i < str.length; i ++){
        res += str[i];
    }
    return res;
}

丑数

题目描述

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

思路

一个丑数肯定是由另一个丑数乘以2或3或5得到。为保持有序性,建立一个丑数数组,维护三个队列,每个队列的队首表示此队列指针对应的丑数乘以2或3或5的结果,每次比较每个队列的队首,取最小的那一个放进丑数数组。直至找到结果。

public int GetUglyNumber_Solution(int index){
    if(index < 0)
        return 0;
    int[] res = new int[index];
    res[0] = 1;  //指定第一个丑数
    //定义三个指针
    int i2 = 0;
    int i3 = 0;
    int i5 = 0;
    int count = 0; //计数变量
    while(count < index){
        int tmp = min(res[i2] * 2, min(res[i3] * 3, res[i5] * 5)); //找出最小的值
        //将最小值的索引加1
        if(tmp == res[i2] * 2) i2++;
        if(tmp == res[i3] * 3) i3++;
        if(tmp == res[i5] * 5) i5++;
        res[++count] = tmp;  //保存结果
    }
    return res[index - 1];
}
public int min(int i, int j){
   return i > j ? j : i;
}

第一个只出现一次的字符

题目描述

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写)。

思路

按照字母的ASCII码值作hash来做数组的索引。A-Z的ASCII码为65-90,a-z对应的ASCII码值为97-122,建立一个大小为58的数组(122 - 65 + 1 = 58),来保存字母的频次,之后再依次遍历字符串个位置字符。

 public int FirstNotRepeatingChar(String str) {
        if(str.length() < 1 || str == null)
            return -1;
        int[] num = new int[58];
        for(int i = 0; i < str.length(); i ++){
            num[str.charAt(i) - 65] += 1;
        }
        for(int i = 0; i < str.length(); i ++){
            if(num[str.charAt(i) - 65] == 1)
                return i;
        }
        return -1;
    }

数组中的逆序对

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

思路

对于逆序对问题,借助归并排序,在归并排序过程中可以计算有多少逆序对。

public int InversePairs(int [] array) {
    if(array.length == 0 || array == null)
        return 0;
    return mergeSort(array, 0, array.length - 1);
}
private int mergeSort(int[] array, int lo, int hi){
    if(hi == lo)
        return 0;
    int mid = lo + ((hi - lo) >> 1);
    return (mergeSort(array, lo, mid) + mergeSort(mid + 1, hi) + merge(array, lo, mid, hi)) % 1000000007;
}
private int merge(int[] array, int lo, int mid, int hi){  //归并是对每一部分(lo, hi)进行归并
    //首先建立一个辅助数组以及一个属于辅助数组的指针
    int[] help = new int[hi - lo + 1];
    int i = 0;
    //定义一个逆序对数的计数值
    int p = 0;
    //定义两个起始点
    int p1 = lo;
    int p2 = mid + 1;
    while(p1 <= mid && p2 <= hi){
        p += array[p1] > array[p2] ? mid - p1 + 1 : 0;
        if(P >  1000000007)
                P = P % 1000000007;
        help[i++] = array[p1] > array[p2] ? array[p2++] : array[p1++];
    }
    while(p1 <= mid){
        help[i++] = array[p1++];
    }
    while(p2 <= hi){
        help[i++] = array[p2++];
    }
    for(int j = 0; j < help.length; j ++){
        array[lo + j] = help[j];
    }
    return p;
}

两个链表的第一个公共结点

题目描述

输入两个链表,找出它们的第一个公共结点。

思路

方法一:使用HashMap,将链表1中的节点放入map中,然后比对链表2中的节点,输出第一个重复的节点。

方法二:采用双指针,一个指向一个链表。让两指针同时行动,当一个指针先到达尾节点时就将其指向另一个链表的表头,直到两指针节点相等。

方法3:先统计两链表长度,计算差值。先让一指针走差值的长度,然后另一链表指针开始走,直至相遇,输出相遇节点。

//方法二
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
    if(pHead1 == null || pHead2 == null)
        return null;
    ListNode p1 = pHead1;
    ListNode p2 = pHead2;
    while(p1 != p2){
        p1 = (p1 == null) ? pHead2 : p1.next;
        p2 = (p2 == null) ? pHead1 : p2.next; 
    }
    return p1;
}

数字在排序数组中出现的次数

题目描述

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

思路

遍历数组,遇到相等的数计数值加1,如果计数值大于1,且当前数不等于该数字,直接break。

public int GetNumberOfK(int [] array , int k) {
    if(array.length == 0 || array == null)
        return 0;
    int count = 0;
    for(int i = 0; i < array.length; i ++){
        if(array[i] == k)
            count ++;
        if(count > 0 && array[i] != k)
            break;
    }
    return count;
}

二叉树的深度

题目描述

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

思路

递归:分别收集左子树和右子树的高度,返回较大值。

非递归:采用层次遍历,使用队列,当从队列中弹出节点数量等于上一层加入队列的节点数时,则深度值加1,知道队列为空。

//递归
public int TreeDepth(TreeNode root) {
    if(root == null)
        return 0;
    int leftDepth = TreeDepth(root.left);
    int rightDepth = TreeDepth(root.right);
    return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}
//非递归
public int TreeDepth(TreeNode root) {
    if(root == null)
        return 0;
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);
    int depth = 0; //深度
    int count = 0; //每一层的计数
    int nextCount = 1; //每层加入队列的节点个数,第一层是root节点,只有一个
    while(!queue.isEmpty()){
        root = queue.poll();
        count++;
        if(!root.left.isEmpty())
            queue.offer(root.left);
        if(!root.right.isEmpty())
            queue.offer(root.right);
        if(count == nextCount){ //一层已经计算完了
            depth ++;
            count = 0; //重新计数下一层
            nextCount = queue.size();
        }
    }
    return depth;
}

平衡二叉树

题目描述

输入一棵二叉树,判断该二叉树是否是平衡二叉树。

思路

收集左子树和右子树的高度,比较两者的大小是否超过1。

public boolean IsBalanced_Solution(TreeNode root) {
    if(root == null)
        return false;
    boolean[] res = new boolean[1];
    res[0] = true;
    getHigth(root, 1, res);
    return res[0];
}

boolean getHigth(TreeNode root, int level, boolean[] res){
    if(root == null)
        return level;
    int lefthigh = getHigth(root.left, level + 1, res);
    if(!res[0])
        return level;
    int righthigh = getHigth(root.right, level + 1, res);
    if(!res[0])
        return level;
    if(Math.abs(lefthigh - righthigh) > 1)
        res[0] = false;
    return Math.max(lefthigh, righthigh);
}

和为S的连续正数序列

题目描述

小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!

思路

连续正数序列是一个公差为1的等差数列,序列的中间值代表平均值的大小。序列的长度为n,则均值为sum/n,由此可以求出序列。但需要考虑n为奇数和偶数的情况。

n为奇数:均值为中间数,条件满足:n & 1 == 1 && sum % n == 0

n为偶数:均值为中间两个数的均值,小数部分我为0.5,sum % n 代表一般的长度,则条件满足:(sum % n)* 2 = n

根据等差数列的求和公式:S = (1 + n) * n / 2,得到n的范围,由题意可知,n至少为2.

public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
       ArrayList<ArrayList<Integer>> alist = new ArrayList<ArrayList<Integer> >();
        for(int n = (int)Math.sqrt(2 * sum); n >= 2; n--){    
            if((n & 1) == 1 && (sum % n == 0) || (sum % n) * 2 == n){
                ArrayList<Integer> blist =new ArrayList<Integer>();
                for(int j = 0, k = ((sum / n) - (n - 1) / 2); j < n; j++, k++){
                    blist.add(k);
                }
                alist.add(blist);
            }
        }
        return alist;
    }

和为S的两个数字

题目描述

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。

思路

考虑到数组递增有序,则需要求的两个数在两头找到的第一对乘积是最小的。

public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
    ArrayList<Integer> list = new ArrayList<Integer>();
    if(array.length < 2 || array == null)
        return list;
    int i = 0;
    int j = array.length - 1;
    while(i < j){
        if(array[i] + array[j] == sum){
            list.add(array[i]);
            list.add(array[j]);
            return list;
        }else if(array[i] + array[j] > sum){
            j--;
        }else{
            i++;
        }
    }
    return list;
}

左旋转字符串

题目描述

汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

思路

方法一:采用substring()直接截取,然后拼接;

方法二:一个一个移过去,实际是从前移到最后;

方法三:YX = (XTYT)T

//方法一
public String LeftRotateString(String str,int n) {
    if(str.length() == 0)
        return "";
    if(n == 0)
        return str;
    String str1 = str.substring(0, n);
    String str2 = str.substring(n, str.length());
    return str2 + str1;
}
//方法二
public String LeftRotateString(String str,int n) {
    if(str.length() == 0)
        return "";
    if(n == 0)
        return str;
    char[] s = str.toCharArray();
    for(int i = 0; i < n; i ++){
        for(int j = 0; j < s.length; j ++)
            swap(s, j, j + 1);
    }
    return String.valueOf(s);
}

void swap(char[] s, int i, int j){
    char tmp = s[i];
    s[i] = s[j];
    s[j] = tmp;
}
//方法三
public String LeftRotateString(String str,int n) {
    char[] chars = str.toCharArray();
        if (chars.length < n) {
            return "";
        }
        reverse(chars, 0, n - 1);
        reverse(chars, n, chars.length - 1);
        reverse(chars, 0, chars.length - 1);
 
        return String.valueOf(chars);
    }
 }
 public void reverse(char[] chars, int start, int end) {
     while (start < end) {
         char temp = chars[start];
         chars[start] = chars[end];
         chars[end] = temp;
         start++;
         end--;
     }
}

翻转单词顺序列

题目描述

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

思路

按空格划分成string数组,然后倒序相加,注意每加一个字符串需要加空格,最后一个不加。

public String ReverseSentence(String str) {
        if(str == null)
            return null;
        if(str.trim().equals("")) //trim()--去掉空格
            return str;
        String[] s = str.split(" ");
        String res = "";
        for(int i = s.length - 1; i >= 0; i--){  
            res += s[i];
            if(i > 0)
                res += " ";
        }
        return res;
    }

扑克牌顺子

题目描述

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。

思路

有序数之间的差值是否有足够的0来填补。

排序后统计0的个数,然后先找到第一个不为0的数,判断前后两个数之间的差是否大于0的个数+1;然后在0的个数大于1的情况下,判断前后两个值是否相等;然后减去已经发生替换的值。在0的个数为0的情况下,判断前后两个数之间差值是否大于1。

 public boolean isContinuous(int [] numbers) {
        if(numbers.length < 5 || numbers == null)
             return false;
        Arrays.sort(numbers);
        int count = 0;
        for(int i = 0; i < numbers.length; i ++){
            if(numbers[i] == 0)
                count++;
        }
        if(count == 4) return true;
        int j = 0;
        while(j < numbers.length - 1){
            while(numbers[j] == 0)  //先找到第一个不是0的值
                j++;
            if(count > 0 && numbers[j + 1] - numbers[j] - 1 > count) //如果两个有序数之间的差大于0的个数
                return false;
            else if(count > 0){
                if(numbers[j + 1] == numbers[j]) //如果有两个数不为0且相等
                    return false;
                count -= (numbers[j + 1] - numbers[j] - 1); //count减去已经替换的数
                j++;
                continue;
            }
            if(count == 0 && (numbers[j + 1] - numbers[j] > 1)) //在没有0的情况下有两个数之间的差值超过2
                return false;
            j++;
        }
        return true;
    }

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

题目描述

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

思路

使用队列,在未到m-1时,让队列里的元素不停的出队并入队;到m-1时只让当前元素出队。

public int LastRemaining_Solution(int n, int m) {
    if(n < 1 || m < 1)
        return -1;
    if(n == 1)
        return 0;
    Queue<Integer> queue = new LinkedList<>();
    for(int i = 0; i < n - 1; i ++)
        queue.offer(i);
    int count = 0;
    while(queue.size() != 1){
        if(count != m - 1){
            queue.offer(queue.poll());
            count++;
        }else{
            queue.poll();
            count = 0;
        }
    }
    return queue.poll();
}

求1+2+3+...+n

题目描述

求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

思路

方法1:采用等差数列求和等式;

方法2:利用递归求和;

//方法1:采用等差数列求和等式
public int Sum_Solution(int n) {
    int sum = (int)Math.pow(n, 2) + n;
    return sum >> 1;
}
//方法2:利用递归求和
public int Sum_Solution(int n) {
    int sum = n;
    if(n == 0)
        return sum;
    return sum + Sum_Solution(n - 1);
}

不用加减乘除做加法

题目描述

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

思路

采用位运算,分别计算个位和进位。

public int Add(int num1,int num2) {
    while(num2 != 0){
        int tmp = num1 ^ num2;  //个位
        num2 = (num1 & num2) << 1;  //进位
        tmp = num1;
    }
    return num1;
}

把字符串转换成整数

题目描述

将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。

思路

首先将字符串转化为字符,并将相应字符通过ASCII码的形式转化为数字。略过第一个字符,判断当前字符是否是字母,是字母直接返回;不是则判断数字当前位数转化为十进制数相加。最后判断正负返回值。

public int StrToInt(String str) {
        if(str.length() < 1 || str == null)
            return 0;
        char[] s = str.toCharArray();
        int[] a = new int[s.length];
        
        for(int i = 0; i < s.length; i++){
            if(s[i]>= 48 && s[i] <= 57)
                a[i] = (s[i] - 48);
        }
        
        int len = a.length - 1;
        int sum = 0;
        for(int i = 0; i < a.length; i++){
            if(i == 0 && (s[i] == '-' || s[i] == '+')){
                continue;    
            }
            if((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z'))
                return 0;
            sum += a[i] *(int)Math.pow(10, len - i);
        }
        if(s[0] == '-')
            sum = (-1) * sum;
        return sum;
   }

数组中重复的数字

题目描述

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

思路

直接记录出现数的次数,遇到第一个出现次数大于1的数记录下来,然后返回。

public boolean duplicate(int numbers[],int length,int [] duplication) {
        int[] flag = new int[10];
        for(int i = 0; i < length; i ++){
            if(flag[numbers[i]] == 1){
                duplication[0] = numbers[i];
                break;
            }else{
                flag[numbers[i]]++;
            }
        }
        return duplication[0] > 0 ? true : false;
    }

按之字形顺序打印二叉树

题目描述

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

思路

方法1:使用LinkedList,在变换打印方向时控制弹出节点和入队节点的方向即可(头部或尾部);

方法2:按照层次遍历的方式,遇到需要变换方向打印的行,将此行调转顺序即可;

//方法1
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> alist = new ArrayList<ArrayList<Integer>>();
        if(pRoot == null)
            return alist;
        boolean flag = true;  //控制之字形的方向
        LinkedList<TreeNode> queue = new LinkedList<>();
        queue.offer(pRoot);
        int count = 0;
        int nextCount = 1;
        ArrayList<Integer> blist = new ArrayList<Integer>();
        while(!queue.isEmpty()){   
            if(flag){  //打印方向变化时只需调整弹出节点和入队节点的方向即可(头部和尾部)
                TreeNode root = queue.pollFirst();
                count++;
                blist.add(root.val);
                if(root.left != null)
                    queue.offerLast(root.left);
                if(root.right != null)
                    queue.offerLast(root.right);
            }else{
                 TreeNode root = queue.pollLast();
                 count++;
                 blist.add(root.val);
                 if(root.right != null)
                     queue.offerFirst(root.right); 
                 if(root.left != null)
                     queue.offerFirst(root.left);
            }
            if(count == nextCount){
                count = 0;
                nextCount = queue.size();
                alist.add(blist);
                blist = new ArrayList<Integer>();   
                flag = !flag;
            }
        }
        return alist;
    }
//方法2
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> alist = new ArrayList<ArrayList<Integer>>();
        if(pRoot == null)
            return alist;
        boolean flag = true;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(pRoot);
        int count = 0;
        int nextCount = 1;
        ArrayList<Integer> blist = new ArrayList<Integer>();
        while(!queue.isEmpty()){           
            TreeNode root = queue.poll();
            count++;
            blist.add(root.val);
            if(root.left != null)
                queue.offer(root.left);
            if(root.right != null)
                queue.offer(root.right);
            if(count == nextCount){
                count = 0;
                nextCount = queue.size();
                if(!flag)
                    alist.add(reverse(blist));
                else
                    alist.add(blist);
                blist = new ArrayList<Integer>();   
                flag = !flag;
            }
        }
        return alist;
    }
     ArrayList<Integer> reverse( ArrayList<Integer> list){
          ArrayList<Integer> res = new  ArrayList<Integer>();
          for(int i = list.size() - 1; i >= 0; i --)
             res.add(list.get(i));
         return res;
     }

题目描述

思路

题目描述

思路

题目描述

思路

题目描述

思路

题目描述

思路

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
水资源是人类社会的宝贵财富,在生活、工农业生产中是不可缺少的。随着世界人口的增长及工农业生产的发展,需水量也在日益增长,水已经变得比以往任何时候都要珍贵。但是,由于人类的生产和生活,导致水体的污染,水质恶化,使有限的水资源更加紧张。长期以来,油类物质(石油类物质和动植物油)一直是水和土壤中的重要污染源。它不仅对人的身体健康带来极大危害,而且使水质恶化,严重破坏水体生态平衡。因此各国都加强了油类物质对水体和土壤的污染的治理。对于水中油含量的检测,我国处于落后阶段,与国际先进水平存在差距,所以难以满足当今技术水平的要求。为了取得具有代表性的正确数据,使分析数据具有与现代测试技术水平相应的准确性和先进性,不断提高分析成果的可比性和应用效果,检测的方法和仪器是非常重要的。只有保证了这两方面才能保证快速和准确地测量出水中油类污染物含量,以达到保护和治理水污染的目的。开展水中油污染检测方法、技术和检测设备的研究,是提高水污染检测的一条重要措施。通过本课题的研究,探索出一套适合我国国情的水质污染现场检测技术和检测设备,具有广泛的应用前景和科学研究价值。 本课题针对我国水体的油污染,探索一套检测油污染的可行方案和方法,利用非分散红外光度法技术,开发研制具有自主知识产权的适合国情的适于野外便携式的测油仪。利用此仪器,可以检测出被测水样中亚甲基、甲基物质和动植物油脂的污染物含量,为我国众多的环境检测站点监测水体的油污染状况提供依据。
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值