2023.4.11 为次日和后天面试前复习内容

4.11 为次日和后天面试前复习内容

详见:《数仓建设学习路线.xmind

常见面试sql题:

  • 连续登录(查询连续登录3天以上用户、查询连续登录最大天数用户) (sum(case …when…then…end))

  • lead/lag使用(股票波峰波谷)(波峰,比前一天,后一天数值都高;波谷相反)

  • 天/月gmv汇总

  • 相互关注

  • 炸裂函数(可用于行列转换问题,

    行转列(split + explode + laterview)
    列转行 ( concat_ws + collect_list/set )

    行列转换问题也可以用sum(case…when …then. .end)(列转行)和union all(行转列)来处理)

  • 排序

  • 每一门课大于60分(意味着最低分大于60)

  • 七日留存

算法题(简单or中等)

  • 快排(mapreduce中shuffle端),时间复杂度nlogn,和冒泡一样,都是交换排序。需要定基准值,一般可以取首值

    写快排就3个主要方法,一个是交换swap,一个是找基准partition,一个是递归过程quick方法,递归直到left >= right 的时候返回

    public class QuickSort{
        public static void main(String[] args){
            int[] arr = {1,3,6,4,5,2,8,7};
            quickSort(arr,0,arr.length-1);
            for(int a : arr){
                System.out.println(a);
            }
        }
    
        public static void quickSort(int[] arr,int L,int R){
             // 递归退出的条件
              if(L < R){
         
                // 随机生成一个数作为基准值
                // swap(arr,L+(int)(Math.random() * (R-L+1)),R);
                // 在数组中随机找一个基准值并与数组最后一个数交换位置
                swap(arr,L+(int)(Math.random() * (R-L+1)),R);
                // 根据标准值进行patition
                int[] p = partition(arr,L,R);
                // 左边递归
                quickSort(arr,L,p[0]-1);
                // 右边递归
                quickSort(arr,p[1]+1,R);
              }
        }
    
        public static int[] partition(int[] arr, int L,int R ) {
           int less = L-1; //左边界的位置
           int more = R; //右边界的位置
            // 判断当前的数的位置是否与右边界more碰撞,发生碰撞就退出循环
           while(L < more){
            if(arr[L] < arr[R]){
                // ++less 和 L++区别就是,在调用swap前,less先自增在传值,
                //L++先传值,等交换完之后在自增,注意方法传参时,先加加(++i)和后加加(i++)的区别
                swap(arr,++less,L++);
            }else if(arr[L] > arr[R]){
                // --more的效果就是把当前遍历到的数与more前面一个进行交换,所以是先--
                swap(arr,--more,L);
            }else{
                // 如果遍历到的数与基准值arr[R]相等就跳过
                L++;
            }
        }
        // 这里就是遍历到的数与大于区域的边界碰撞时,把基准值与大于区域的第一个数进行交换
        // 那么基准值的位置就确定了
        swap(arr,more,R);
        // 然后把基准值的数组所在的范围返回
        return new int[] {less+1,more};
    } 
    
        public static void swap(int[] arr,int i,int j){
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    

    另外版本:好理解,但是时间复杂度高些:0(n^2)

    public class Quicksort {
        public void quicksort(int[] a, int low,int high){
            int start = low;
            int end = high;
            int key = a[low];//基准值
            while (end > start){
                //从后往前遍历
                while(end > start && a[end] >= key){
                    //没有比基准值小的,则比较下一个,直到有比关键值小的交换位置
                    end--;
                    if (a[end] <= key){
                        int temp = key;
                        a[end] = a[start];
                        a[start] = temp;
                    }
                }
                //从前往后比较
                while (end > start && a[start] <= key){
                    //如果没有比基准值大的,比较下一个,直到有比关键值大的交换位置
                    start++;
                    if (a[start] >= key){
                        int temp = a[start];
                        a[start] = a[end];
                        a[end] = temp;
    
                    }
                    //此时第一次循环比较结束,关键值的位置已经确定。左边的值都比关键值小,右边的都比关键值大,
                    //但是两边的顺序还有可能是不一样的,进行下面的递归调用
    
                }
                //递归
                if (start > low){
                    quicksort(a,low,start - 1);
                }
                if (end < high){
                    quicksort(a,end + 1,high);
                }
    
            }
    
        }
    }
    
  • 归并排序(mapreduce中reduce端),时间复杂度nlogn,空间复杂度O(n),相同元素的前后顺序并没有改变,所以是一种稳定排序算法

    import java.util.Arrays;
     
    public class Gui {
     
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		int arr[] = {6,5,3,1,8,7,2,4};
    		mergeSort(arr,0,arr.length-1);
    		System.out.println("排序结果:"+Arrays.toString(arr));
     
    	}
    	public static void mergeSort(int[] a, int low, int high) {
    		//首先判断 low 和 high是否指向一个地方
               // 正常情况下就是 == 
    		if(low == high) {
    			return;
    		}
    		int mid = (low + high)/2;
    		//先递归左边
    		mergeSort(a, low, mid);
    		//在递归右边
    		mergeSort(a, mid+1, high);
    		//合并
    		merge(a,low,mid,high);
    		System.out.println(Arrays.toString(a));
        }
    	//合并
    	public static void merge(int[] a,int low,int mid,int high) {
    		//定义第一段
    		int s1 = low;
    		//定义第二段
    		int s2 = mid+1;
    		//定义临时数组
    		int[] temp =new int[high-low+1];
    		int i = 0;
    		
    		//判断s1,s2是否有数据,放入临时数组
    		while(s1<=mid) {
    			temp[i++]=a[s1++];
    		}
    		while(s2<=high) {
    			temp[i++]=a[s2++];
    		}
    		for(int j = 0;j < temp.length;j++) {
    			a[j+low]=temp[j];
    		}
    	}
    	
     
    }
    
  • 二分查找

    定义好,左右边界,mid = left + (right - left) / 2,while(left <= right)

    左闭右闭区间

    class Solution {
        public int search(int[] nums, int target) {
            // 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
            if (target < nums[0] || target > nums[nums.length - 1]) {
                return -1;
            }
            int left = 0, right = nums.length - 1;
            while (left <= right) {
                int mid = left + ((right - left) >> 1);
                if (nums[mid] == target)
                    return mid;
                else if (nums[mid] < target)
                    left = mid + 1;
                else if (nums[mid] > target)
                    right = mid - 1;
            }
            return -1;
        }
    }
    
  • 链表反序

    双指针法,两指针cur,pre,cur指向头结点,pre初始化null

    // 双指针
    class Solution {
        public ListNode reverseList(ListNode head) {
            ListNode prev = null;
            ListNode cur = head;
            ListNode temp = null;
            while (cur != null) {
                temp = cur.next;// 保存下一个节点
                cur.next = prev;
                prev = cur;
                cur = temp;
            }
            return prev;
        }
    }
    
  • 两数之和

    可暴力,可哈希表Hashmap,存(nums[i],i)

    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];
        if(nums == null || nums.length == 0){
            return res;
        }
        Map<Integer, Integer> map = new HashMap<>();
        for(int i = 0; i < nums.length; i++){
            int temp = target - nums[i];   // 遍历当前元素,并在map中寻找是否有匹配的key
            if(map.containsKey(temp)){
                res[1] = i;
                res[0] = map.get(temp);
                break;
            }
            map.put(nums[i], i);    // 如果没找到匹配对,就把访问过的元素和下标加入到map中
        }
        return res;
    }
    

mapreduce/spark

数据倾斜如何调优

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值